~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/memory/root.cc

Remove dead memset call.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
/* Routines to handle mallocing of results which will be freed the same time */
 
16
/**
 
17
 * @file
 
18
 * Routines to handle mallocing of results which will be freed the same time 
 
19
 */
17
20
 
18
21
#include "config.h"
19
22
 
30
33
static const unsigned int MAX_BLOCK_TO_DROP= 4096;
31
34
static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
32
35
 
33
 
/*
34
 
  Initialize memory root
35
 
 
36
 
  SYNOPSIS
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)
43
 
 
44
 
  DESCRIPTION
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.
50
 
*/
51
 
 
52
 
void memory::init_alloc_root(memory::Root *mem_root, size_t block_size)
 
36
/**
 
37
 * @brief
 
38
 * Initialize memory root
 
39
 *
 
40
 * @details
 
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.
 
46
 *
 
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)
 
52
 *
 
53
 */
 
54
void memory::Root::init_alloc_root(size_t block_size_arg)
53
55
{
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;
60
 
 
61
 
  return;
 
56
  free= used= pre_alloc= 0;
 
57
  min_malloc= 32;
 
58
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
 
59
  error_handler= 0;
 
60
  block_num= 4;                 /* We shift this with >>2 */
 
61
  first_block_usage= 0;
62
62
}
63
63
 
64
64
 
65
 
/*
66
 
  SYNOPSIS
67
 
    reset_root_defaults()
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'.
75
 
  DESCRIPTION
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
79
 
    before allocation.
80
 
*/
81
 
 
82
 
void memory::reset_root_defaults(memory::Root *mem_root, size_t block_size,
83
 
                                 size_t pre_alloc_size)
 
65
/**
 
66
 * @details
 
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
 
70
 * before allocation.
 
71
 *
 
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'.
 
79
 */
 
80
void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
84
81
{
85
 
  assert(alloc_root_inited(mem_root));
86
 
 
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)
89
84
  {
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)
92
87
    {
93
 
      memory::internal::UsedMemory *mem, **prev= &mem_root->free;
 
88
      memory::internal::UsedMemory *mem, **prev= &this->free;
94
89
      /*
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)
102
97
        {
103
98
          /* We found a suitable block, no need to do anything else */
104
 
          mem_root->pre_alloc= mem;
 
99
          pre_alloc= mem;
105
100
          return;
106
101
        }
107
102
        if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
108
103
        {
109
104
          /* remove block from the list and free it */
110
105
          *prev= mem->next;
111
 
          free(mem);
 
106
          std::free(mem);
112
107
        }
113
108
        else
114
109
          prev= &mem->next;
119
114
        mem->size= size;
120
115
        mem->left= pre_alloc_size;
121
116
        mem->next= *prev;
122
 
        *prev= mem_root->pre_alloc= mem;
 
117
        *prev= pre_alloc= mem;
123
118
      }
124
119
      else
125
120
      {
126
 
        mem_root->pre_alloc= 0;
 
121
        pre_alloc= 0;
127
122
      }
128
123
    }
129
124
  }
130
125
  else
131
126
  {
132
 
    mem_root->pre_alloc= 0;
 
127
    pre_alloc= 0;
133
128
  }
134
129
}
135
130
 
136
 
 
137
 
void *memory::alloc_root(memory::Root *mem_root, size_t length)
 
131
/**
 
132
 * @brief 
 
133
 * Allocate a chunk of memory from the Root structure provided, 
 
134
 * obtaining more memory from the heap if necessary
 
135
 *
 
136
 * @pre
 
137
 * mem_root must have been initialised via init_alloc_root()
 
138
 *
 
139
 * @param  mem_root  The memory Root to allocate from
 
140
 * @param  length    The size of the block to allocate
 
141
 *
 
142
 * @todo Would this be more suitable as a member function on the
 
143
 * Root class?
 
144
 */
 
145
void *memory::Root::alloc_root(size_t length)
138
146
{
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());
144
151
 
145
152
  length= ALIGN_SIZE(length);
146
 
  if ((*(prev= &mem_root->free)) != NULL)
 
153
  if ((*(prev= &this->free)) != NULL)
147
154
  {
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)
151
158
    {
152
159
      next= *prev;
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;
 
162
      this->used= next;
 
163
      this->first_block_usage= 0;
157
164
    }
158
165
    for (next= *prev ; next && next->left < length ; next= next->next)
159
166
      prev= &next->next;
160
167
  }
161
168
  if (! 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;
 
171
 
 
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);
166
175
 
167
176
    if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
168
177
    {
169
 
      if (mem_root->error_handler)
170
 
        (*mem_root->error_handler)();
 
178
      if (this->error_handler)
 
179
        (*this->error_handler)();
171
180
      return NULL;
172
181
    }
173
 
    mem_root->block_num++;
 
182
    this->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));
178
187
  }
179
188
 
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;
 
195
    this->used= next;
 
196
    this->first_block_usage= 0;
188
197
  }
189
 
  return((void*) point);
 
198
 
 
199
  return point;
190
200
}
191
201
 
192
202
 
193
 
/*
194
 
  Allocate many pointers at the same time.
195
 
 
196
 
  DESCRIPTION
197
 
    ptr1, ptr2, etc all point into big allocated memory area.
198
 
 
199
 
  SYNOPSIS
200
 
    multi_alloc_root()
201
 
      root               Memory root
202
 
      ptr1, length1      Multiple arguments terminated by a NULL pointer
203
 
      ptr2, length2      ...
204
 
      ...
205
 
      NULL
206
 
 
207
 
  RETURN VALUE
208
 
    A pointer to the beginning of the allocated memory block
209
 
    in case of success or NULL if out of memory.
210
 
*/
211
 
 
212
 
void *memory::multi_alloc_root(memory::Root *root, ...)
 
203
/**
 
204
 * @brief
 
205
 * Allocate many pointers at the same time.
 
206
 *
 
207
 * @details
 
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>
 
214
 * @li <tt>...</tt>
 
215
 * @li <tt>NULL</tt>
 
216
 *
 
217
 * @c pointer1, @c pointer2 etc. all point into big allocated memory area
 
218
 *
 
219
 * @param root  Memory root
 
220
 *
 
221
 * @return
 
222
 * A pointer to the beginning of the allocated memory block in case of 
 
223
 * success or NULL if out of memory
 
224
 */
 
225
void *memory::Root::multi_alloc_root(int unused, ...)
213
226
{
214
227
  va_list args;
215
228
  char **ptr, *start, *res;
216
229
  size_t tot_length, length;
217
230
 
218
 
  va_start(args, root);
 
231
  (void)unused; // For some reason Sun Studio registers unused as not used.
 
232
  va_start(args, unused);
219
233
  tot_length= 0;
220
234
  while ((ptr= va_arg(args, char **)))
221
235
  {
224
238
  }
225
239
  va_end(args);
226
240
 
227
 
  if (!(start= (char*) memory::alloc_root(root, tot_length)))
 
241
  if (!(start= (char*) this->alloc_root(tot_length)))
228
242
    return(0);
229
243
 
230
 
  va_start(args, root);
 
244
  va_start(args, unused);
231
245
  res= start;
232
246
  while ((ptr= va_arg(args, char **)))
233
247
  {
241
255
 
242
256
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
243
257
 
244
 
/* Mark all data in blocks free for reusage */
245
 
 
246
 
static inline void mark_blocks_free(memory::Root* root)
 
258
/**
 
259
 * @brief
 
260
 * Mark all data in blocks free for reusage 
 
261
 */
 
262
void memory::Root::mark_blocks_free()
247
263
{
248
264
  memory::internal::UsedMemory *next;
249
265
  memory::internal::UsedMemory **last;
250
266
 
251
267
  /* iterate through (partially) free blocks, mark them free */
252
 
  last= &root->free;
253
 
  for (next= root->free; next; next= *(last= &next->next))
 
268
  last= &free;
 
269
  for (next= free; next; next= *(last= &next->next))
254
270
  {
255
271
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
256
272
    TRASH_MEM(next);
257
273
  }
258
274
 
259
275
  /* Combine the free and the used list */
260
 
  *last= next=root->used;
 
276
  *last= next= used;
261
277
 
262
278
  /* now go through the used blocks and mark them free */
263
279
  for (; next; next= next->next)
267
283
  }
268
284
 
269
285
  /* Now everything is set; Indicate that nothing is used anymore */
270
 
  root->used= 0;
271
 
  root->first_block_usage= 0;
 
286
  used= 0;
 
287
  first_block_usage= 0;
272
288
}
273
289
 
274
 
 
275
 
/*
276
 
  Deallocate everything used by memory::alloc_root or just move
277
 
  used blocks to free list if called with MY_USED_TO_FREE
278
 
 
279
 
  SYNOPSIS
280
 
    free_root()
281
 
      root              Memory root
282
 
      MyFlags           Flags for what should be freed:
283
 
 
284
 
        MARK_BLOCKS_FREED       Don't free blocks, just mark them free
285
 
        KEEP_PREALLOC           If this is not set, then free also the
286
 
                                preallocated block
287
 
 
288
 
  NOTES
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.
292
 
*/
293
 
 
294
 
void memory::free_root(memory::Root *root, myf MyFlags)
 
290
/**
 
291
 * @brief
 
292
 * Deallocate everything used by memory::alloc_root or just move
 
293
 * used blocks to free list if called with MY_USED_TO_FREE
 
294
 *
 
295
 * @note
 
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.
 
299
 *
 
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
 
304
 *                              preallocated block
 
305
 */
 
306
void memory::Root::free_root(myf MyFlags)
295
307
{
296
308
  memory::internal::UsedMemory *next,*old;
297
309
 
298
310
  if (MyFlags & memory::MARK_BLOCKS_FREE)
299
311
  {
300
 
    mark_blocks_free(root);
 
312
    this->mark_blocks_free();
301
313
    return;
302
314
  }
303
315
  if (!(MyFlags & memory::KEEP_PREALLOC))
304
 
    root->pre_alloc=0;
 
316
    this->pre_alloc=0;
305
317
 
306
 
  for (next=root->used; next ;)
 
318
  for (next=this->used; next ;)
307
319
  {
308
320
    old=next; next= next->next ;
309
 
    if (old != root->pre_alloc)
310
 
      free(old);
 
321
    if (old != this->pre_alloc)
 
322
      std::free(old);
311
323
  }
312
 
  for (next=root->free ; next ;)
 
324
  for (next=this->free ; next ;)
313
325
  {
314
326
    old=next; next= next->next;
315
 
    if (old != root->pre_alloc)
316
 
      free(old);
317
 
  }
318
 
  root->used=root->free=0;
319
 
  if (root->pre_alloc)
320
 
  {
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);
324
 
    root->free->next=0;
325
 
  }
326
 
  root->block_num= 4;
327
 
  root->first_block_usage= 0;
328
 
  return;
329
 
}
330
 
 
331
 
/*
332
 
  Find block that contains an object and set the pre_alloc to it
333
 
*/
334
 
 
335
 
void memory::set_prealloc_root(memory::Root *root, char *ptr)
336
 
{
337
 
  memory::internal::UsedMemory *next;
338
 
  for (next=root->used; next ; next=next->next)
339
 
  {
340
 
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
341
 
    {
342
 
      root->pre_alloc=next;
343
 
      return;
344
 
    }
345
 
  }
346
 
  for (next=root->free ; next ; next=next->next)
347
 
  {
348
 
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
349
 
    {
350
 
      root->pre_alloc=next;
351
 
      return;
352
 
    }
353
 
  }
354
 
}
355
 
 
356
 
 
357
 
char *memory::strdup_root(memory::Root *root, const char *str)
358
 
{
359
 
  return strmake_root(root, str, strlen(str));
360
 
}
361
 
 
362
 
 
363
 
char *memory::strmake_root(memory::Root *root, const char *str, size_t len)
 
327
    if (old != this->pre_alloc)
 
328
      std::free(old);
 
329
  }
 
330
  this->used=this->free=0;
 
331
  if (this->pre_alloc)
 
332
  {
 
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);
 
336
    this->free->next=0;
 
337
  }
 
338
  this->block_num= 4;
 
339
  this->first_block_usage= 0;
 
340
}
 
341
 
 
342
/**
 
343
 * @brief
 
344
 * Duplicate a null-terminated string into memory allocated from within the
 
345
 * specified Root
 
346
 */
 
347
char *memory::Root::strdup_root(const char *str)
 
348
{
 
349
  return strmake_root(str, strlen(str));
 
350
}
 
351
 
 
352
/**
 
353
 * @brief
 
354
 * Copy the (not necessarily null-terminated) string into memory allocated
 
355
 * from within the specified Root
 
356
 *
 
357
 * @details
 
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
 
361
 * this purpose).
 
362
 */
 
363
char *memory::Root::strmake_root(const char *str, size_t len)
364
364
{
365
365
  char *pos;
366
 
  if ((pos=(char *)memory::alloc_root(root,len+1)))
 
366
  if ((pos= (char *)alloc_root(len+1)))
367
367
  {
368
368
    memcpy(pos,str,len);
369
369
    pos[len]=0;
371
371
  return pos;
372
372
}
373
373
 
374
 
 
375
 
void *memory::memdup_root(memory::Root *root, const void *str, size_t len)
 
374
/**
 
375
 * @brief
 
376
 * Duplicate the provided block into memory allocated from within the specified
 
377
 * Root
 
378
 *
 
379
 * @return
 
380
 * non-NULL pointer to a copy of the data if memory could be allocated, otherwise
 
381
 * NULL
 
382
 */
 
383
void *memory::Root::memdup_root(const void *str, size_t len)
376
384
{
377
385
  void *pos;
378
 
  if ((pos=memory::alloc_root(root,len)))
 
386
 
 
387
  if ((pos= this->alloc_root(len)))
379
388
    memcpy(pos,str,len);
 
389
 
380
390
  return pos;
381
391
}
382
392