GNU libmicrohttpd  0.9.29
memorypool.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (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 
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 
38 #define ALIGN_SIZE (2 * sizeof(void*))
39 
43 #define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1)))
44 
45 
50 struct MemoryPool
51 {
52 
56  char *memory;
57 
61  size_t size;
62 
66  size_t pos;
67 
71  size_t end;
72 
76  int is_mmap;
77 };
78 
79 
86 struct MemoryPool *
87 MHD_pool_create (size_t max)
88 {
89  struct MemoryPool *pool;
90 
91  pool = malloc (sizeof (struct MemoryPool));
92  if (NULL == pool)
93  return NULL;
94 #if defined(MAP_ANONYMOUS) || defined(_WIN32)
95  if (max <= 32 * 1024)
96  pool->memory = MAP_FAILED;
97  else
98 #if defined(MAP_ANONYMOUS) && !defined(_WIN32)
99  pool->memory = mmap (NULL, max, PROT_READ | PROT_WRITE,
100  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
101 #elif defined(_WIN32)
102  pool->memory = VirtualAlloc(NULL, max, MEM_COMMIT | MEM_RESERVE,
103  PAGE_READWRITE);
104 #endif
105 #else
106  pool->memory = MAP_FAILED;
107 #endif
108  if ((pool->memory == MAP_FAILED) || (pool->memory == NULL))
109  {
110  pool->memory = malloc (max);
111  if (pool->memory == NULL)
112  {
113  free (pool);
114  return NULL;
115  }
116  pool->is_mmap = MHD_NO;
117  }
118  else
119  {
120  pool->is_mmap = MHD_YES;
121  }
122  pool->pos = 0;
123  pool->end = max;
124  pool->size = max;
125  return pool;
126 }
127 
128 
134 void
135 MHD_pool_destroy (struct MemoryPool *pool)
136 {
137  if (pool == NULL)
138  return;
139  if (pool->is_mmap == MHD_NO)
140  free (pool->memory);
141  else
142 #if defined(MAP_ANONYMOUS) && !defined(_WIN32)
143  munmap (pool->memory, pool->size);
144 #elif defined(_WIN32)
145  VirtualFree(pool->memory, 0, MEM_RELEASE);
146 #else
147  abort();
148 #endif
149  free (pool);
150 }
151 
152 
164 void *
165 MHD_pool_allocate (struct MemoryPool *pool,
166  size_t size, int from_end)
167 {
168  void *ret;
169  size_t asize;
170 
171  asize = ROUND_TO_ALIGN (size);
172  if ( (0 == asize) && (0 != size) )
173  return NULL; /* size too close to SIZE_MAX */
174  if ((pool->pos + asize > pool->end) || (pool->pos + asize < pool->pos))
175  return NULL;
176  if (from_end == MHD_YES)
177  {
178  ret = &pool->memory[pool->end - asize];
179  pool->end -= asize;
180  }
181  else
182  {
183  ret = &pool->memory[pool->pos];
184  pool->pos += asize;
185  }
186  return ret;
187 }
188 
189 
207 void *
208 MHD_pool_reallocate (struct MemoryPool *pool,
209  void *old,
210  size_t old_size,
211  size_t new_size)
212 {
213  void *ret;
214  size_t asize;
215 
216  asize = ROUND_TO_ALIGN (new_size);
217  if ( (0 == asize) && (0 != new_size) )
218  return NULL; /* new_size too close to SIZE_MAX */
219  if ((pool->end < old_size) || (pool->end < asize))
220  return NULL; /* unsatisfiable or bogus request */
221 
222  if ( (pool->pos >= old_size) &&
223  (&pool->memory[pool->pos - old_size] == old) )
224  {
225  /* was the previous allocation - optimize! */
226  if (pool->pos + asize - old_size <= pool->end)
227  {
228  /* fits */
229  pool->pos += asize - old_size;
230  if (asize < old_size) /* shrinking - zero again! */
231  memset (&pool->memory[pool->pos], 0, old_size - asize);
232  return old;
233  }
234  /* does not fit */
235  return NULL;
236  }
237  if (asize <= old_size)
238  return old; /* cannot shrink, no need to move */
239  if ((pool->pos + asize >= pool->pos) &&
240  (pool->pos + asize <= pool->end))
241  {
242  /* fits */
243  ret = &pool->memory[pool->pos];
244  memmove (ret, old, old_size);
245  pool->pos += asize;
246  return ret;
247  }
248  /* does not fit */
249  return NULL;
250 }
251 
252 
266 void *
267 MHD_pool_reset (struct MemoryPool *pool,
268  void *keep,
269  size_t copy_bytes,
270  size_t new_size)
271 {
272  if (NULL != keep)
273  {
274  if (keep != pool->memory)
275  {
276  memmove (pool->memory,
277  keep,
278  copy_bytes);
279  keep = pool->memory;
280  }
281  }
282  pool->end = pool->size;
283  /* technically not needed, but safer to zero out */
284  memset (&pool->memory[copy_bytes],
285  0,
286  pool->size - copy_bytes);
287  if (NULL != keep)
288  pool->pos = ROUND_TO_ALIGN (new_size);
289  return keep;
290 }
291 
292 
293 /* end of memorypool.c */
void * MHD_pool_reset(struct MemoryPool *pool, void *keep, size_t copy_bytes, size_t new_size)
Definition: memorypool.c:267
#define NULL
Definition: reason_phrase.c:30
void MHD_pool_destroy(struct MemoryPool *pool)
Definition: memorypool.c:135
#define MHD_YES
Definition: microhttpd.h:138
void * MHD_pool_allocate(struct MemoryPool *pool, size_t size, int from_end)
Definition: memorypool.c:165
#define MAP_FAILED
Definition: memorypool.c:32
void * MHD_pool_reallocate(struct MemoryPool *pool, void *old, size_t old_size, size_t new_size)
Definition: memorypool.c:208
#define ROUND_TO_ALIGN(n)
Definition: memorypool.c:43
struct MemoryPool * MHD_pool_create(size_t max)
Definition: memorypool.c:87
#define MHD_NO
Definition: microhttpd.h:143
memory pool; mostly used for efficient (de)allocation for each connection and bounding memory use for...