aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/memorypool.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-05-05 18:07:33 +0000
committerChristian Grothoff <christian@grothoff.org>2013-05-05 18:07:33 +0000
commit9eb27c8dbe1939344ccced9c498895f0e92e8197 (patch)
treea97d1b7caf1e5dc79c22b08d58be70bc8c205cba /src/microhttpd/memorypool.c
parent1725bcf3c546fccbf22d7794bf7290fcc28c385d (diff)
downloadlibmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.tar.gz
libmicrohttpd-9eb27c8dbe1939344ccced9c498895f0e92e8197.zip
-changing directory name
Diffstat (limited to 'src/microhttpd/memorypool.c')
-rw-r--r--src/microhttpd/memorypool.c261
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 */
50struct 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 */
86struct MemoryPool *
87MHD_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 */
126void
127MHD_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 */
150void *
151MHD_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 */
190void *
191MHD_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 */
241void *
242MHD_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 */