diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-05-05 18:07:33 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-05-05 18:07:33 +0000 |
commit | 9eb27c8dbe1939344ccced9c498895f0e92e8197 (patch) | |
tree | a97d1b7caf1e5dc79c22b08d58be70bc8c205cba /src/microhttpd/memorypool.c | |
parent | 1725bcf3c546fccbf22d7794bf7290fcc28c385d (diff) | |
download | libmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.tar.gz libmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.zip |
-changing directory name
Diffstat (limited to 'src/microhttpd/memorypool.c')
-rw-r--r-- | src/microhttpd/memorypool.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/src/microhttpd/memorypool.c b/src/microhttpd/memorypool.c new file mode 100644 index 00000000..bd7c0c3a --- /dev/null +++ b/src/microhttpd/memorypool.c | |||
@@ -0,0 +1,261 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | /** | ||
21 | * @file memorypool.c | ||
22 | * @brief memory pool | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "memorypool.h" | ||
26 | |||
27 | /* define MAP_ANONYMOUS for Mac OS X */ | ||
28 | #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) | ||
29 | #define MAP_ANONYMOUS MAP_ANON | ||
30 | #endif | ||
31 | #ifndef MAP_FAILED | ||
32 | #define MAP_FAILED ((void*)-1) | ||
33 | #endif | ||
34 | |||
35 | /** | ||
36 | * Align to 2x word size (as GNU libc does). | ||
37 | */ | ||
38 | #define ALIGN_SIZE (2 * sizeof(void*)) | ||
39 | |||
40 | /** | ||
41 | * Round up 'n' to a multiple of ALIGN_SIZE. | ||
42 | */ | ||
43 | #define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1))) | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Handle for a memory pool. Pools are not reentrant and must not be | ||
48 | * used by multiple threads. | ||
49 | */ | ||
50 | struct MemoryPool | ||
51 | { | ||
52 | |||
53 | /** | ||
54 | * Pointer to the pool's memory | ||
55 | */ | ||
56 | char *memory; | ||
57 | |||
58 | /** | ||
59 | * Size of the pool. | ||
60 | */ | ||
61 | size_t size; | ||
62 | |||
63 | /** | ||
64 | * Offset of the first unallocated byte. | ||
65 | */ | ||
66 | size_t pos; | ||
67 | |||
68 | /** | ||
69 | * Offset of the last unallocated byte. | ||
70 | */ | ||
71 | size_t end; | ||
72 | |||
73 | /** | ||
74 | * MHD_NO if pool was malloc'ed, MHD_YES if mmapped. | ||
75 | */ | ||
76 | int is_mmap; | ||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Create a memory pool. | ||
82 | * | ||
83 | * @param max maximum size of the pool | ||
84 | * @return NULL on error | ||
85 | */ | ||
86 | struct MemoryPool * | ||
87 | MHD_pool_create (size_t max) | ||
88 | { | ||
89 | struct MemoryPool *pool; | ||
90 | |||
91 | pool = malloc (sizeof (struct MemoryPool)); | ||
92 | if (pool == NULL) | ||
93 | return NULL; | ||
94 | #ifdef MAP_ANONYMOUS | ||
95 | pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE, | ||
96 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
97 | #else | ||
98 | pool->memory = MAP_FAILED; | ||
99 | #endif | ||
100 | if ((pool->memory == MAP_FAILED) || (pool->memory == NULL)) | ||
101 | { | ||
102 | pool->memory = malloc (max); | ||
103 | if (pool->memory == NULL) | ||
104 | { | ||
105 | free (pool); | ||
106 | return NULL; | ||
107 | } | ||
108 | pool->is_mmap = MHD_NO; | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | pool->is_mmap = MHD_YES; | ||
113 | } | ||
114 | pool->pos = 0; | ||
115 | pool->end = max; | ||
116 | pool->size = max; | ||
117 | return pool; | ||
118 | } | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Destroy a memory pool. | ||
123 | * | ||
124 | * @param pool memory pool to destroy | ||
125 | */ | ||
126 | void | ||
127 | MHD_pool_destroy (struct MemoryPool *pool) | ||
128 | { | ||
129 | if (pool == NULL) | ||
130 | return; | ||
131 | if (pool->is_mmap == MHD_NO) | ||
132 | free (pool->memory); | ||
133 | else | ||
134 | MUNMAP (pool->memory, pool->size); | ||
135 | free (pool); | ||
136 | } | ||
137 | |||
138 | |||
139 | /** | ||
140 | * Allocate size bytes from the pool. | ||
141 | * | ||
142 | * @param pool memory pool to use for the operation | ||
143 | * @param size number of bytes to allocate | ||
144 | * @param from_end allocate from end of pool (set to MHD_YES); | ||
145 | * use this for small, persistent allocations that | ||
146 | * will never be reallocated | ||
147 | * @return NULL if the pool cannot support size more | ||
148 | * bytes | ||
149 | */ | ||
150 | void * | ||
151 | MHD_pool_allocate (struct MemoryPool *pool, | ||
152 | size_t size, int from_end) | ||
153 | { | ||
154 | void *ret; | ||
155 | |||
156 | size = ROUND_TO_ALIGN (size); | ||
157 | if ((pool->pos + size > pool->end) || (pool->pos + size < pool->pos)) | ||
158 | return NULL; | ||
159 | if (from_end == MHD_YES) | ||
160 | { | ||
161 | ret = &pool->memory[pool->end - size]; | ||
162 | pool->end -= size; | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | ret = &pool->memory[pool->pos]; | ||
167 | pool->pos += size; | ||
168 | } | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Reallocate a block of memory obtained from the pool. | ||
175 | * This is particularly efficient when growing or | ||
176 | * shrinking the block that was last (re)allocated. | ||
177 | * If the given block is not the most recenlty | ||
178 | * (re)allocated block, the memory of the previous | ||
179 | * allocation may be leaked until the pool is | ||
180 | * destroyed (and copying the data maybe required). | ||
181 | * | ||
182 | * @param pool memory pool to use for the operation | ||
183 | * @param old the existing block | ||
184 | * @param old_size the size of the existing block | ||
185 | * @param new_size the new size of the block | ||
186 | * @return new address of the block, or | ||
187 | * NULL if the pool cannot support new_size | ||
188 | * bytes (old continues to be valid for old_size) | ||
189 | */ | ||
190 | void * | ||
191 | MHD_pool_reallocate (struct MemoryPool *pool, | ||
192 | void *old, | ||
193 | size_t old_size, | ||
194 | size_t new_size) | ||
195 | { | ||
196 | void *ret; | ||
197 | |||
198 | new_size = ROUND_TO_ALIGN (new_size); | ||
199 | if ((pool->end < old_size) || (pool->end < new_size)) | ||
200 | return NULL; /* unsatisfiable or bogus request */ | ||
201 | |||
202 | if ((pool->pos >= old_size) && (&pool->memory[pool->pos - old_size] == old)) | ||
203 | { | ||
204 | /* was the previous allocation - optimize! */ | ||
205 | if (pool->pos + new_size - old_size <= pool->end) | ||
206 | { | ||
207 | /* fits */ | ||
208 | pool->pos += new_size - old_size; | ||
209 | if (new_size < old_size) /* shrinking - zero again! */ | ||
210 | memset (&pool->memory[pool->pos], 0, old_size - new_size); | ||
211 | return old; | ||
212 | } | ||
213 | /* does not fit */ | ||
214 | return NULL; | ||
215 | } | ||
216 | if (new_size <= old_size) | ||
217 | return old; /* cannot shrink, no need to move */ | ||
218 | if ((pool->pos + new_size >= pool->pos) && | ||
219 | (pool->pos + new_size <= pool->end)) | ||
220 | { | ||
221 | /* fits */ | ||
222 | ret = &pool->memory[pool->pos]; | ||
223 | memcpy (ret, old, old_size); | ||
224 | pool->pos += new_size; | ||
225 | return ret; | ||
226 | } | ||
227 | /* does not fit */ | ||
228 | return NULL; | ||
229 | } | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Clear all entries from the memory pool except | ||
234 | * for "keep" of the given "size". | ||
235 | * | ||
236 | * @param pool memory pool to use for the operation | ||
237 | * @param keep pointer to the entry to keep (maybe NULL) | ||
238 | * @param size how many bytes need to be kept at this address | ||
239 | * @return addr new address of "keep" (if it had to change) | ||
240 | */ | ||
241 | void * | ||
242 | MHD_pool_reset (struct MemoryPool *pool, | ||
243 | void *keep, | ||
244 | size_t size) | ||
245 | { | ||
246 | size = ROUND_TO_ALIGN (size); | ||
247 | if (keep != NULL) | ||
248 | { | ||
249 | if (keep != pool->memory) | ||
250 | { | ||
251 | memmove (pool->memory, keep, size); | ||
252 | keep = pool->memory; | ||
253 | } | ||
254 | pool->pos = size; | ||
255 | } | ||
256 | pool->end = pool->size; | ||
257 | return keep; | ||
258 | } | ||
259 | |||
260 | |||
261 | /* end of memorypool.c */ | ||