Mercurial > dovecot > original-hg > dovecot-1.2
annotate src/lib/mempool-alloconly.c @ 330:1b503c732877 HEAD
more ANSI-C fixes.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 29 Sep 2002 20:47:41 +0300 |
parents | 4a7ab9e94f25 |
children | 849f3846212a |
rev | line source |
---|---|
0 | 1 /* |
2 mempool-alloconly.c : Memory pool for fast allocation of memory without | |
3 need to free it in small blocks | |
4 | |
5 Copyright (c) 2002 Timo Sirainen | |
6 | |
7 Permission is hereby granted, free of charge, to any person obtaining | |
8 a copy of this software and associated documentation files (the | |
9 "Software"), to deal in the Software without restriction, including | |
10 without limitation the rights to use, copy, modify, merge, publish, | |
11 distribute, sublicense, and/or sell copies of the Software, and to | |
12 permit persons to whom the Software is furnished to do so, subject to | |
13 the following conditions: | |
14 | |
15 The above copyright notice and this permission notice shall be | |
16 included in all copies or substantial portions of the Software. | |
17 | |
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
21 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
22 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
25 */ | |
26 | |
27 #include "lib.h" | |
28 #include "mempool.h" | |
29 | |
30 #include <stdlib.h> | |
31 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
32 #define MAX_ALLOC_SIZE SSIZE_T_MAX |
0 | 33 |
34 typedef struct _PoolBlock PoolBlock; | |
35 | |
36 typedef struct { | |
37 struct Pool pool; | |
38 int refcount; | |
39 | |
40 PoolBlock *block; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
41 size_t last_alloc_size; |
0 | 42 |
43 char name[MEM_ALIGN_SIZE]; /* variable size */ | |
44 } AlloconlyPool; | |
45 #define SIZEOF_ALLOCONLYPOOL (sizeof(AlloconlyPool)-MEM_ALIGN_SIZE) | |
46 | |
47 struct _PoolBlock { | |
48 PoolBlock *prev; | |
49 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
50 size_t size; |
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
51 size_t left; |
0 | 52 |
72 | 53 /* unsigned char data[]; */ |
0 | 54 }; |
72 | 55 #define SIZEOF_POOLBLOCK (MEM_ALIGN(sizeof(PoolBlock))) |
56 | |
57 #define POOL_BLOCK_DATA(block) \ | |
58 ((char *) (block) + SIZEOF_POOLBLOCK) | |
0 | 59 |
60 typedef struct { | |
67
b28ac4106d5a
Allocated memory wasn't aligned according to MEM_ALIGN_SIZE.
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
61 union { |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
62 size_t size; |
67
b28ac4106d5a
Allocated memory wasn't aligned according to MEM_ALIGN_SIZE.
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
63 unsigned char alignment[MEM_ALIGN_SIZE]; |
b28ac4106d5a
Allocated memory wasn't aligned according to MEM_ALIGN_SIZE.
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
64 } size; |
0 | 65 unsigned char data[MEM_ALIGN_SIZE]; /* variable size */ |
66 } PoolAlloc; | |
67 #define SIZEOF_POOLALLOC (sizeof(PoolAlloc)-MEM_ALIGN_SIZE) | |
68 | |
330 | 69 static void pool_alloconly_ref(Pool pool); |
70 static void pool_alloconly_unref(Pool pool); | |
71 static void *pool_alloconly_malloc(Pool pool, size_t size); | |
72 static void pool_alloconly_free(Pool pool, void *mem); | |
73 static void *pool_alloconly_realloc(Pool pool, void *mem, size_t size); | |
74 static void *pool_alloconly_realloc_min(Pool pool, void *mem, size_t size); | |
0 | 75 static void pool_alloconly_clear(Pool pool); |
76 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
77 static void block_alloc(AlloconlyPool *pool, size_t size); |
330 | 78 |
79 static struct Pool static_alloconly_pool = { | |
80 pool_alloconly_ref, | |
81 pool_alloconly_unref, | |
82 | |
83 pool_alloconly_malloc, | |
84 pool_alloconly_free, | |
85 | |
86 pool_alloconly_realloc, | |
87 pool_alloconly_realloc_min, | |
88 | |
89 pool_alloconly_clear | |
90 }; | |
0 | 91 |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
92 Pool pool_alloconly_create(const char *name, size_t size) |
0 | 93 { |
94 AlloconlyPool *apool; | |
95 int len; | |
96 | |
97 len = strlen(name); | |
98 | |
99 apool = calloc(SIZEOF_ALLOCONLYPOOL + len+1, 1); | |
100 apool->pool = static_alloconly_pool; | |
101 apool->refcount = 1; | |
102 | |
103 block_alloc(apool, size); | |
104 | |
105 strcpy(apool->name, name); | |
106 return (Pool) apool; | |
107 } | |
108 | |
109 static void pool_alloconly_destroy(AlloconlyPool *apool) | |
110 { | |
111 /* destroy all but the last block */ | |
112 pool_alloconly_clear(&apool->pool); | |
113 | |
114 /* destroy the last block */ | |
115 free(apool->block); | |
116 free(apool); | |
117 } | |
118 | |
119 static void pool_alloconly_ref(Pool pool) | |
120 { | |
121 AlloconlyPool *apool = (AlloconlyPool *) pool; | |
122 | |
123 apool->refcount++; | |
124 } | |
125 | |
126 static void pool_alloconly_unref(Pool pool) | |
127 { | |
128 AlloconlyPool *apool = (AlloconlyPool *) pool; | |
129 | |
130 if (--apool->refcount == 0) | |
131 pool_alloconly_destroy(apool); | |
132 } | |
133 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
134 static void block_alloc(AlloconlyPool *apool, size_t size) |
0 | 135 { |
136 PoolBlock *block; | |
137 | |
138 /* each block is at least twice the size of the previous one */ | |
139 if (apool->block != NULL) | |
140 size += apool->block->size; | |
141 | |
72 | 142 if (size <= SIZEOF_POOLBLOCK) |
143 size += SIZEOF_POOLBLOCK; | |
0 | 144 size = nearest_power(size); |
145 | |
146 block = calloc(size, 1); | |
147 block->prev = apool->block; | |
148 apool->block = block; | |
149 | |
150 block->size = size - SIZEOF_POOLBLOCK; | |
151 block->left = block->size; | |
152 } | |
153 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
154 static void *pool_alloconly_malloc(Pool pool, size_t size) |
0 | 155 { |
156 AlloconlyPool *apool = (AlloconlyPool *) pool; | |
157 PoolAlloc *alloc; | |
158 | |
159 size = MEM_ALIGN(size); | |
160 | |
161 if (apool->block->left < size + SIZEOF_POOLALLOC) { | |
162 /* we need a new block */ | |
163 block_alloc(apool, size); | |
164 } | |
165 | |
72 | 166 alloc = (PoolAlloc *) (POOL_BLOCK_DATA(apool->block) + |
0 | 167 apool->block->size - apool->block->left); |
67
b28ac4106d5a
Allocated memory wasn't aligned according to MEM_ALIGN_SIZE.
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
168 alloc->size.size = size; |
0 | 169 |
170 apool->block->left -= size + SIZEOF_POOLALLOC; | |
171 apool->last_alloc_size = size; | |
172 return alloc->data; | |
173 } | |
174 | |
175 static void pool_alloconly_free(Pool pool __attr_unused__, | |
176 void *mem __attr_unused__) | |
177 { | |
178 /* ignore */ | |
179 } | |
180 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
181 static void *pool_alloconly_realloc(Pool pool, void *mem, size_t size) |
0 | 182 { |
183 /* there's no point in shrinking the memory usage, | |
184 so just do the same as realloc_min() */ | |
185 return pool_alloconly_realloc_min(pool, mem, size); | |
186 } | |
187 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
188 static int pool_try_grow(AlloconlyPool *apool, void *mem, size_t size) |
0 | 189 { |
190 /* see if we want to grow the memory we allocated last */ | |
72 | 191 if (POOL_BLOCK_DATA(apool->block) + (apool->block->size - |
192 apool->block->left - | |
193 apool->last_alloc_size) == mem) { | |
0 | 194 /* yeah, see if we can grow */ |
195 if (apool->block->left >= size-apool->last_alloc_size) { | |
196 /* just shrink the available size */ | |
197 apool->block->left -= size - apool->last_alloc_size; | |
198 apool->last_alloc_size = size; | |
199 return TRUE; | |
200 } | |
201 } | |
202 | |
203 return FALSE; | |
204 } | |
205 | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
206 static void *pool_alloconly_realloc_min(Pool pool, void *mem, size_t size) |
0 | 207 { |
208 AlloconlyPool *apool = (AlloconlyPool *) pool; | |
209 PoolAlloc *alloc; | |
210 unsigned char *new_mem; | |
183
4a7ab9e94f25
size_t fixes for lib/. Changed OFF_T_FORMAT to PRIuOFF_T which is more
Timo Sirainen <tss@iki.fi>
parents:
72
diff
changeset
|
211 size_t old_size; |
0 | 212 |
213 if (mem == NULL) { | |
214 alloc = NULL; | |
215 old_size = 0; | |
216 } else { | |
217 /* get old size */ | |
218 alloc = (PoolAlloc *) ((char *) mem - SIZEOF_POOLALLOC); | |
67
b28ac4106d5a
Allocated memory wasn't aligned according to MEM_ALIGN_SIZE.
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
219 old_size = alloc->size.size; |
0 | 220 } |
221 | |
222 if (old_size >= size) | |
223 return mem; | |
224 | |
225 size = MEM_ALIGN(size); | |
226 | |
227 /* see if we can directly grow it */ | |
228 if (pool_try_grow(apool, mem, size)) | |
229 return mem; | |
230 | |
231 /* slow way - allocate + copy */ | |
232 new_mem = pool_alloconly_malloc(pool, size); | |
233 if (size > old_size) { | |
234 /* clear new data */ | |
235 memset(new_mem + old_size, 0, size - old_size); | |
236 } | |
237 | |
238 return new_mem; | |
239 } | |
240 | |
241 static void pool_alloconly_clear(Pool pool) | |
242 { | |
243 AlloconlyPool *apool = (AlloconlyPool *) pool; | |
244 PoolBlock *block; | |
245 | |
246 /* destroy all blocks but the last, which is the largest */ | |
247 while (apool->block->prev != NULL) { | |
248 block = apool->block; | |
249 apool->block = block->prev; | |
250 | |
251 free(block); | |
252 } | |
253 | |
254 /* clear the last block */ | |
72 | 255 memset(POOL_BLOCK_DATA(apool->block), 0, |
256 apool->block->size - apool->block->left); | |
0 | 257 apool->block->left = apool->block->size; |
258 | |
259 apool->last_alloc_size = 0; | |
260 } |