~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/* Routines to handle mallocing of results which will be freed the same time */
17
685.1.3 by Monty Taylor
Turned off stdinc - and then fixed the carnage.
18
#include "mysys_priv.h"
212.5.39 by Monty Taylor
Phew. Moved my_base and my_global.
19
#include <mystrings/m_string.h>
1 by brian
clean slate
20
21
22
/*
23
  Initialize memory root
24
25
  SYNOPSIS
26
    init_alloc_root()
27
      mem_root       - memory root to initialize
28
      block_size     - size of chunks (blocks) used for memory allocation
29
                       (It is external size of chunk i.e. it should include
30
                        memory required for internal structures, thus it
31
                        should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
32
      pre_alloc_size - if non-0, then size of block that should be
33
                       pre-allocated during memory root initialization.
34
35
  DESCRIPTION
36
    This function prepares memory root for further use, sets initial size of
37
    chunk for memory allocation and pre-allocates first block if specified.
38
    Altough error can happen during execution of this function if
39
    pre_alloc_size is non-0 it won't be reported. Instead it will be
40
    reported as error in first alloc_root() on this memory root.
41
*/
42
43
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
44
		     size_t )
1 by brian
clean slate
45
{
46
  mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
47
  mem_root->min_malloc= 32;
48
  mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
49
  mem_root->error_handler= 0;
50
  mem_root->block_num= 4;			/* We shift this with >>2 */
51
  mem_root->first_block_usage= 0;
52
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
53
  return;
1 by brian
clean slate
54
}
55
56
57
/*
58
  SYNOPSIS
59
    reset_root_defaults()
60
    mem_root        memory root to change defaults of
61
    block_size      new value of block size. Must be greater or equal
62
                    than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
63
                    68 bytes and depends on platform and compilation flags)
64
    pre_alloc_size  new size of preallocated block. If not zero,
65
                    must be equal to or greater than block size,
66
                    otherwise means 'no prealloc'.
67
  DESCRIPTION
68
    Function aligns and assigns new value to block size; then it tries to
69
    reuse one of existing blocks as prealloc block, or malloc new one of
70
    requested size. If no blocks can be reused, all unused blocks are freed
71
    before allocation.
72
*/
73
74
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
75
                         size_t pre_alloc_size)
1 by brian
clean slate
76
{
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
77
  assert(alloc_root_inited(mem_root));
1 by brian
clean slate
78
79
  mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
80
  if (pre_alloc_size)
81
  {
82
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
83
    if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
84
    {
85
      USED_MEM *mem, **prev= &mem_root->free;
86
      /*
87
        Free unused blocks, so that consequent calls
88
        to reset_root_defaults won't eat away memory.
89
      */
90
      while (*prev)
91
      {
92
        mem= *prev;
93
        if (mem->size == size)
94
        {
95
          /* We found a suitable block, no need to do anything else */
96
          mem_root->pre_alloc= mem;
97
          return;
98
        }
99
        if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
100
        {
101
          /* remove block from the list and free it */
102
          *prev= mem->next;
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
103
          free(mem);
1 by brian
clean slate
104
        }
105
        else
106
          prev= &mem->next;
107
      }
108
      /* Allocate new prealloc block and add it to the end of free list */
656.3.1 by Monty Taylor
Got rid of my_once_alloc.
109
      if ((mem= (USED_MEM *) malloc(size)))
1 by brian
clean slate
110
      {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
111
        mem->size= size;
1 by brian
clean slate
112
        mem->left= pre_alloc_size;
113
        mem->next= *prev;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
114
        *prev= mem_root->pre_alloc= mem;
1 by brian
clean slate
115
      }
116
      else
117
      {
118
        mem_root->pre_alloc= 0;
119
      }
120
    }
121
  }
122
  else
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
123
  {
1 by brian
clean slate
124
    mem_root->pre_alloc= 0;
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
125
  }
1 by brian
clean slate
126
}
127
128
129
void *alloc_root(MEM_ROOT *mem_root, size_t length)
130
{
131
  size_t get_size, block_size;
481 by Brian Aker
Remove all of uchar.
132
  unsigned char* point;
1 by brian
clean slate
133
  register USED_MEM *next= 0;
134
  register USED_MEM **prev;
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
135
  assert(alloc_root_inited(mem_root));
1 by brian
clean slate
136
137
  length= ALIGN_SIZE(length);
138
  if ((*(prev= &mem_root->free)) != NULL)
139
  {
140
    if ((*prev)->left < length &&
141
	mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
142
	(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
143
    {
144
      next= *prev;
145
      *prev= next->next;			/* Remove block from list */
146
      next->next= mem_root->used;
147
      mem_root->used= next;
148
      mem_root->first_block_usage= 0;
149
    }
150
    for (next= *prev ; next && next->left < length ; next= next->next)
151
      prev= &next->next;
152
  }
153
  if (! next)
154
  {						/* Time to alloc new block */
155
    block_size= mem_root->block_size * (mem_root->block_num >> 2);
156
    get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
398.1.4 by Monty Taylor
Renamed max/min.
157
    get_size= cmax(get_size, block_size);
1 by brian
clean slate
158
656.3.1 by Monty Taylor
Got rid of my_once_alloc.
159
    if (!(next = (USED_MEM*) malloc(get_size)))
1 by brian
clean slate
160
    {
161
      if (mem_root->error_handler)
162
	(*mem_root->error_handler)();
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
163
      return((void*) 0);                      /* purecov: inspected */
1 by brian
clean slate
164
    }
165
    mem_root->block_num++;
166
    next->next= *prev;
167
    next->size= get_size;
168
    next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
169
    *prev=next;
170
  }
171
481 by Brian Aker
Remove all of uchar.
172
  point= (unsigned char*) ((char*) next+ (next->size-next->left));
1 by brian
clean slate
173
  /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
174
  if ((next->left-= length) < mem_root->min_malloc)
175
  {						/* Full block */
176
    *prev= next->next;				/* Remove block from list */
177
    next->next= mem_root->used;
178
    mem_root->used= next;
179
    mem_root->first_block_usage= 0;
180
  }
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
181
  return((void*) point);
1 by brian
clean slate
182
}
183
184
185
/*
186
  Allocate many pointers at the same time.
187
188
  DESCRIPTION
189
    ptr1, ptr2, etc all point into big allocated memory area.
190
191
  SYNOPSIS
192
    multi_alloc_root()
193
      root               Memory root
194
      ptr1, length1      Multiple arguments terminated by a NULL pointer
195
      ptr2, length2      ...
196
      ...
197
      NULL
198
199
  RETURN VALUE
200
    A pointer to the beginning of the allocated memory block
201
    in case of success or NULL if out of memory.
202
*/
203
204
void *multi_alloc_root(MEM_ROOT *root, ...)
205
{
206
  va_list args;
207
  char **ptr, *start, *res;
208
  size_t tot_length, length;
209
210
  va_start(args, root);
211
  tot_length= 0;
212
  while ((ptr= va_arg(args, char **)))
213
  {
214
    length= va_arg(args, uint);
215
    tot_length+= ALIGN_SIZE(length);
216
  }
217
  va_end(args);
218
219
  if (!(start= (char*) alloc_root(root, tot_length)))
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
220
    return(0);                            /* purecov: inspected */
1 by brian
clean slate
221
222
  va_start(args, root);
223
  res= start;
224
  while ((ptr= va_arg(args, char **)))
225
  {
226
    *ptr= res;
227
    length= va_arg(args, uint);
228
    res+= ALIGN_SIZE(length);
229
  }
230
  va_end(args);
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
231
  return((void*) start);
1 by brian
clean slate
232
}
233
234
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
235
236
/* Mark all data in blocks free for reusage */
237
238
static inline void mark_blocks_free(MEM_ROOT* root)
239
{
240
  register USED_MEM *next;
241
  register USED_MEM **last;
242
243
  /* iterate through (partially) free blocks, mark them free */
244
  last= &root->free;
245
  for (next= root->free; next; next= *(last= &next->next))
246
  {
247
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
248
    TRASH_MEM(next);
249
  }
250
251
  /* Combine the free and the used list */
252
  *last= next=root->used;
253
254
  /* now go through the used blocks and mark them free */
255
  for (; next; next= next->next)
256
  {
257
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
258
    TRASH_MEM(next);
259
  }
260
261
  /* Now everything is set; Indicate that nothing is used anymore */
262
  root->used= 0;
263
  root->first_block_usage= 0;
264
}
265
266
267
/*
268
  Deallocate everything used by alloc_root or just move
269
  used blocks to free list if called with MY_USED_TO_FREE
270
271
  SYNOPSIS
272
    free_root()
273
      root		Memory root
274
      MyFlags		Flags for what should be freed:
275
276
        MY_MARK_BLOCKS_FREED	Don't free blocks, just mark them free
277
        MY_KEEP_PREALLOC	If this is not set, then free also the
278
        		        preallocated block
279
280
  NOTES
281
    One can call this function either with root block initialised with
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
282
    init_alloc_root() or with a zero:ed block.
1 by brian
clean slate
283
    It's also safe to call this multiple times with the same mem_root.
284
*/
285
286
void free_root(MEM_ROOT *root, myf MyFlags)
287
{
288
  register USED_MEM *next,*old;
289
290
  if (MyFlags & MY_MARK_BLOCKS_FREE)
291
  {
292
    mark_blocks_free(root);
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
293
    return;
1 by brian
clean slate
294
  }
295
  if (!(MyFlags & MY_KEEP_PREALLOC))
296
    root->pre_alloc=0;
297
298
  for (next=root->used; next ;)
299
  {
300
    old=next; next= next->next ;
301
    if (old != root->pre_alloc)
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
302
      free(old);
1 by brian
clean slate
303
  }
304
  for (next=root->free ; next ;)
305
  {
306
    old=next; next= next->next;
307
    if (old != root->pre_alloc)
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
308
      free(old);
1 by brian
clean slate
309
  }
310
  root->used=root->free=0;
311
  if (root->pre_alloc)
312
  {
313
    root->free=root->pre_alloc;
314
    root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
315
    TRASH_MEM(root->pre_alloc);
316
    root->free->next=0;
317
  }
318
  root->block_num= 4;
319
  root->first_block_usage= 0;
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
320
  return;
1 by brian
clean slate
321
}
322
323
/*
324
  Find block that contains an object and set the pre_alloc to it
325
*/
326
327
void set_prealloc_root(MEM_ROOT *root, char *ptr)
328
{
329
  USED_MEM *next;
330
  for (next=root->used; next ; next=next->next)
331
  {
332
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
333
    {
334
      root->pre_alloc=next;
335
      return;
336
    }
337
  }
338
  for (next=root->free ; 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
}
347
348
349
char *strdup_root(MEM_ROOT *root, const char *str)
350
{
351
  return strmake_root(root, str, strlen(str));
352
}
353
354
355
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
356
{
357
  char *pos;
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
358
  if ((pos=(char *)alloc_root(root,len+1)))
1 by brian
clean slate
359
  {
360
    memcpy(pos,str,len);
361
    pos[len]=0;
362
  }
363
  return pos;
364
}
365
366
367
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
368
{
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
369
  void *pos;
1 by brian
clean slate
370
  if ((pos=alloc_root(root,len)))
371
    memcpy(pos,str,len);
372
  return pos;
373
}