1 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 
3    This library is free software; you can redistribute it and/or
4    modify it under the terms of the GNU Library General Public
5    License as published by the Free Software Foundation; either
6    version 2 of the License, or (at your option) any later version.
7 
8    This library 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 GNU
11    Library General Public License for more details.
12 
13    You should have received a copy of the GNU Library General Public
14    License along with this library; if not, write to the Free
15    Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16    MA 02111-1301, USA */
17 
18 /* Routines to handle mallocing of results which will be freed the same time */
19 
20 #include <ma_global.h>
21 #include <ma_sys.h>
22 #include <ma_string.h>
23 
ma_init_alloc_root(MA_MEM_ROOT * mem_root,size_t block_size,size_t pre_alloc_size)24 void ma_init_alloc_root(MA_MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size)
25 {
26   mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
27   mem_root->min_malloc=32;
28   mem_root->block_size= (block_size-MALLOC_OVERHEAD-sizeof(MA_USED_MEM)+8);
29   mem_root->error_handler=0;
30   mem_root->block_num= 4;
31   mem_root->first_block_usage= 0;
32 #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
33   if (pre_alloc_size)
34   {
35     if ((mem_root->free = mem_root->pre_alloc=
36 	 (MA_USED_MEM*) malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(MA_USED_MEM)))))
37     {
38       mem_root->free->size=pre_alloc_size+ALIGN_SIZE(sizeof(MA_USED_MEM));
39       mem_root->free->left=pre_alloc_size;
40       mem_root->free->next=0;
41     }
42   }
43 #endif
44 }
45 
ma_alloc_root(MA_MEM_ROOT * mem_root,size_t Size)46 void * ma_alloc_root(MA_MEM_ROOT *mem_root, size_t Size)
47 {
48 #if defined(HAVE_purify) && defined(EXTRA_DEBUG)
49   reg1 MA_USED_MEM *next;
50   Size+=ALIGN_SIZE(sizeof(MA_USED_MEM));
51 
52   if (!(next = (MA_USED_MEM*) malloc(Size)))
53   {
54     if (mem_root->error_handler)
55       (*mem_root->error_handler)();
56     return((void *) 0);				/* purecov: inspected */
57   }
58   next->next=mem_root->used;
59   mem_root->used=next;
60   return (void *) (((char*) next)+ALIGN_SIZE(sizeof(MA_USED_MEM)));
61 #else
62   size_t get_size;
63   void * point;
64   reg1 MA_USED_MEM *next= 0;
65   reg2 MA_USED_MEM **prev;
66 
67   Size= ALIGN_SIZE(Size);
68 
69   if ((*(prev= &mem_root->free)))
70   {
71     if ((*prev)->left < Size &&
72         mem_root->first_block_usage++ >= 16 &&
73         (*prev)->left < 4096)
74     {
75       next= *prev;
76       *prev= next->next;
77       next->next= mem_root->used;
78       mem_root->used= next;
79       mem_root->first_block_usage= 0;
80     }
81     for (next= *prev; next && next->left < Size; next= next->next)
82       prev= &next->next;
83   }
84 
85   if (! next)
86   {						/* Time to alloc new block */
87     get_size= MAX(Size+ALIGN_SIZE(sizeof(MA_USED_MEM)),
88               (mem_root->block_size & ~1) * (mem_root->block_num >> 2));
89 
90     if (!(next = (MA_USED_MEM*) malloc(get_size)))
91     {
92       if (mem_root->error_handler)
93 	(*mem_root->error_handler)();
94       return((void *) 0);				/* purecov: inspected */
95     }
96     mem_root->block_num++;
97     next->next= *prev;
98     next->size= get_size;
99     next->left= get_size-ALIGN_SIZE(sizeof(MA_USED_MEM));
100     *prev=next;
101   }
102   point= (void *) ((char*) next+ (next->size-next->left));
103   if ((next->left-= Size) < mem_root->min_malloc)
104   {						/* Full block */
105     *prev=next->next;				/* Remove block from list */
106     next->next=mem_root->used;
107     mem_root->used=next;
108     mem_root->first_block_usage= 0;
109   }
110   return(point);
111 #endif
112 }
113 
114 	/* deallocate everything used by alloc_root */
115 
ma_free_root(MA_MEM_ROOT * root,myf MyFlags)116 void ma_free_root(MA_MEM_ROOT *root, myf MyFlags)
117 {
118   reg1 MA_USED_MEM *next,*old;
119 
120   if (!root)
121     return; /* purecov: inspected */
122   if (!(MyFlags & MY_KEEP_PREALLOC))
123     root->pre_alloc=0;
124 
125   for ( next=root->used; next ;)
126   {
127     old=next; next= next->next ;
128     if (old != root->pre_alloc)
129       free(old);
130   }
131   for (next= root->free ; next ; )
132   {
133     old=next; next= next->next ;
134     if (old != root->pre_alloc)
135       free(old);
136   }
137   root->used=root->free=0;
138   if (root->pre_alloc)
139   {
140     root->free=root->pre_alloc;
141     root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(MA_USED_MEM));
142     root->free->next=0;
143   }
144 }
145 
146 
ma_strdup_root(MA_MEM_ROOT * root,const char * str)147 char *ma_strdup_root(MA_MEM_ROOT *root,const char *str)
148 {
149   size_t len= strlen(str)+1;
150   char *pos;
151   if ((pos=ma_alloc_root(root,len)))
152     memcpy(pos,str,len);
153   return pos;
154 }
155 
156 
ma_memdup_root(MA_MEM_ROOT * root,const char * str,size_t len)157 char *ma_memdup_root(MA_MEM_ROOT *root, const char *str, size_t len)
158 {
159   char *pos;
160   if ((pos= ma_alloc_root(root,len)))
161     memcpy(pos,str,len);
162   return pos;
163 }
164 
ma_multi_malloc(myf myFlags,...)165 void *ma_multi_malloc(myf myFlags, ...)
166 {
167   va_list args;
168   char **ptr,*start,*res;
169   size_t tot_length,length;
170 
171   va_start(args,myFlags);
172   tot_length=0;
173   while ((ptr=va_arg(args, char **)))
174   {
175     length=va_arg(args, size_t);
176     tot_length+=ALIGN_SIZE(length);
177   }
178   va_end(args);
179 
180   if (!(start=(char *)malloc(tot_length)))
181     return 0;
182 
183   va_start(args,myFlags);
184   res=start;
185   while ((ptr=va_arg(args, char **)))
186   {
187     *ptr=res;
188     length=va_arg(args,size_t);
189     res+=ALIGN_SIZE(length);
190   }
191   va_end(args);
192   return start;
193 }
194