|
Packit |
875988 |
/*
|
|
Packit |
875988 |
This file is part of libmicrohttpd
|
|
Packit |
875988 |
Copyright (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
|
|
Packit |
875988 |
|
|
Packit |
875988 |
This library is free software; you can redistribute it and/or
|
|
Packit |
875988 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
875988 |
License as published by the Free Software Foundation; either
|
|
Packit |
875988 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
This library is distributed in the hope that it will be useful,
|
|
Packit |
875988 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
875988 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
875988 |
Lesser General Public License for more details.
|
|
Packit |
875988 |
|
|
Packit |
875988 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
875988 |
License along with this library; if not, write to the Free Software
|
|
Packit |
875988 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* @file memorypool.c
|
|
Packit |
875988 |
* @brief memory pool
|
|
Packit |
875988 |
* @author Christian Grothoff
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#include "memorypool.h"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* define MAP_ANONYMOUS for Mac OS X */
|
|
Packit |
875988 |
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
|
|
Packit |
875988 |
#define MAP_ANONYMOUS MAP_ANON
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
#ifndef MAP_FAILED
|
|
Packit |
875988 |
#define MAP_FAILED ((void*)-1)
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Align to 2x word size (as GNU libc does).
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define ALIGN_SIZE (2 * sizeof(void*))
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Round up 'n' to a multiple of ALIGN_SIZE.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1)))
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Handle for a memory pool. Pools are not reentrant and must not be
|
|
Packit |
875988 |
* used by multiple threads.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MemoryPool
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Pointer to the pool's memory
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
char *memory;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Size of the pool.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
size_t size;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Offset of the first unallocated byte.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
size_t pos;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Offset of the last unallocated byte.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
size_t end;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* #MHD_NO if pool was malloc'ed, #MHD_YES if mmapped (VirtualAlloc'ed for W32).
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int is_mmap;
|
|
Packit |
875988 |
};
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Free the memory given by @a ptr. Calls "free(ptr)". This function
|
|
Packit |
875988 |
* should be used to free the username returned by
|
|
Packit |
875988 |
* #MHD_digest_auth_get_username().
|
|
Packit |
875988 |
* @note Since v0.9.56
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param ptr pointer to free.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
_MHD_EXTERN void
|
|
Packit |
875988 |
MHD_free (void *ptr)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (ptr);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a memory pool.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param max maximum size of the pool
|
|
Packit |
875988 |
* @return NULL on error
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MemoryPool *
|
|
Packit |
875988 |
MHD_pool_create (size_t max)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MemoryPool *pool;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
pool = malloc (sizeof (struct MemoryPool));
|
|
Packit |
875988 |
if (NULL == pool)
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
#if defined(MAP_ANONYMOUS) || defined(_WIN32)
|
|
Packit |
875988 |
if (max <= 32 * 1024)
|
|
Packit |
875988 |
pool->memory = MAP_FAILED;
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
#if defined(MAP_ANONYMOUS) && !defined(_WIN32)
|
|
Packit |
875988 |
pool->memory = mmap (NULL,
|
|
Packit |
875988 |
max,
|
|
Packit |
875988 |
PROT_READ | PROT_WRITE,
|
|
Packit |
875988 |
MAP_PRIVATE | MAP_ANONYMOUS,
|
|
Packit |
875988 |
-1,
|
|
Packit |
875988 |
0);
|
|
Packit |
875988 |
#elif defined(_WIN32)
|
|
Packit |
875988 |
pool->memory = VirtualAlloc (NULL,
|
|
Packit |
875988 |
max,
|
|
Packit |
875988 |
MEM_COMMIT | MEM_RESERVE,
|
|
Packit |
875988 |
PAGE_READWRITE);
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
#else
|
|
Packit |
875988 |
pool->memory = MAP_FAILED;
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
if ( (MAP_FAILED == pool->memory) ||
|
|
Packit |
875988 |
(NULL == pool->memory))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
pool->memory = malloc (max);
|
|
Packit |
875988 |
if (NULL == pool->memory)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (pool);
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
pool->is_mmap = MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
pool->is_mmap = MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
pool->pos = 0;
|
|
Packit |
875988 |
pool->end = max;
|
|
Packit |
875988 |
pool->size = max;
|
|
Packit |
875988 |
return pool;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Destroy a memory pool.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param pool memory pool to destroy
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
void
|
|
Packit |
875988 |
MHD_pool_destroy (struct MemoryPool *pool)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (NULL == pool)
|
|
Packit |
875988 |
return;
|
|
Packit |
875988 |
if (MHD_NO == pool->is_mmap)
|
|
Packit |
875988 |
free (pool->memory);
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
#if defined(MAP_ANONYMOUS) && !defined(_WIN32)
|
|
Packit |
875988 |
munmap (pool->memory,
|
|
Packit |
875988 |
pool->size);
|
|
Packit |
875988 |
#elif defined(_WIN32)
|
|
Packit |
875988 |
VirtualFree (pool->memory,
|
|
Packit |
875988 |
0,
|
|
Packit |
875988 |
MEM_RELEASE);
|
|
Packit |
875988 |
#else
|
|
Packit |
875988 |
abort ();
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
free (pool);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Check how much memory is left in the @a pool
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param pool pool to check
|
|
Packit |
875988 |
* @return number of bytes still available in @a pool
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
size_t
|
|
Packit |
875988 |
MHD_pool_get_free (struct MemoryPool *pool)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return (pool->end - pool->pos);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Allocate size bytes from the pool.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param pool memory pool to use for the operation
|
|
Packit |
875988 |
* @param size number of bytes to allocate
|
|
Packit |
875988 |
* @param from_end allocate from end of pool (set to #MHD_YES);
|
|
Packit |
875988 |
* use this for small, persistent allocations that
|
|
Packit |
875988 |
* will never be reallocated
|
|
Packit |
875988 |
* @return NULL if the pool cannot support size more
|
|
Packit |
875988 |
* bytes
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
void *
|
|
Packit |
875988 |
MHD_pool_allocate (struct MemoryPool *pool,
|
|
Packit |
875988 |
size_t size,
|
|
Packit |
875988 |
int from_end)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
void *ret;
|
|
Packit |
875988 |
size_t asize;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
asize = ROUND_TO_ALIGN (size);
|
|
Packit |
875988 |
if ( (0 == asize) && (0 != size) )
|
|
Packit |
875988 |
return NULL; /* size too close to SIZE_MAX */
|
|
Packit |
875988 |
if ( (pool->pos + asize > pool->end) ||
|
|
Packit |
875988 |
(pool->pos + asize < pool->pos))
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
if (from_end == MHD_YES)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
ret = &pool->memory[pool->end - asize];
|
|
Packit |
875988 |
pool->end -= asize;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
ret = &pool->memory[pool->pos];
|
|
Packit |
875988 |
pool->pos += asize;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return ret;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Reallocate a block of memory obtained from the pool.
|
|
Packit |
875988 |
* This is particularly efficient when growing or
|
|
Packit |
875988 |
* shrinking the block that was last (re)allocated.
|
|
Packit |
875988 |
* If the given block is not the most recently
|
|
Packit |
875988 |
* (re)allocated block, the memory of the previous
|
|
Packit |
875988 |
* allocation may be leaked until the pool is
|
|
Packit |
875988 |
* destroyed (and copying the data maybe required).
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param pool memory pool to use for the operation
|
|
Packit |
875988 |
* @param old the existing block
|
|
Packit |
875988 |
* @param old_size the size of the existing block
|
|
Packit |
875988 |
* @param new_size the new size of the block
|
|
Packit |
875988 |
* @return new address of the block, or
|
|
Packit |
875988 |
* NULL if the pool cannot support @a new_size
|
|
Packit |
875988 |
* bytes (old continues to be valid for @a old_size)
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
void *
|
|
Packit |
875988 |
MHD_pool_reallocate (struct MemoryPool *pool,
|
|
Packit |
875988 |
void *old,
|
|
Packit |
875988 |
size_t old_size,
|
|
Packit |
875988 |
size_t new_size)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
void *ret;
|
|
Packit |
875988 |
size_t asize;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
asize = ROUND_TO_ALIGN (new_size);
|
|
Packit |
875988 |
if ( (0 == asize) &&
|
|
Packit |
875988 |
(0 != new_size) )
|
|
Packit |
875988 |
return NULL; /* new_size too close to SIZE_MAX */
|
|
Packit |
875988 |
if ( (pool->end < old_size) ||
|
|
Packit |
875988 |
(pool->end < asize) )
|
|
Packit |
875988 |
return NULL; /* unsatisfiable or bogus request */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (pool->pos >= old_size) &&
|
|
Packit |
875988 |
(&pool->memory[pool->pos - old_size] == old) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* was the previous allocation - optimize! */
|
|
Packit |
875988 |
if (pool->pos + asize - old_size <= pool->end)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* fits */
|
|
Packit |
875988 |
pool->pos += asize - old_size;
|
|
Packit |
875988 |
if (asize < old_size) /* shrinking - zero again! */
|
|
Packit |
875988 |
memset (&pool->memory[pool->pos],
|
|
Packit |
875988 |
0,
|
|
Packit |
875988 |
old_size - asize);
|
|
Packit |
875988 |
return old;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* does not fit */
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (asize <= old_size)
|
|
Packit |
875988 |
return old; /* cannot shrink, no need to move */
|
|
Packit |
875988 |
if ((pool->pos + asize >= pool->pos) &&
|
|
Packit |
875988 |
(pool->pos + asize <= pool->end))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* fits */
|
|
Packit |
875988 |
ret = &pool->memory[pool->pos];
|
|
Packit |
875988 |
if (0 != old_size)
|
|
Packit |
875988 |
memmove (ret,
|
|
Packit |
875988 |
old,
|
|
Packit |
875988 |
old_size);
|
|
Packit |
875988 |
pool->pos += asize;
|
|
Packit |
875988 |
return ret;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* does not fit */
|
|
Packit |
875988 |
return NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Clear all entries from the memory pool except
|
|
Packit |
875988 |
* for @a keep of the given @a size. The pointer
|
|
Packit |
875988 |
* returned should be a buffer of @a new_size where
|
|
Packit |
875988 |
* the first @a copy_bytes are from @a keep.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param pool memory pool to use for the operation
|
|
Packit |
875988 |
* @param keep pointer to the entry to keep (maybe NULL)
|
|
Packit |
875988 |
* @param copy_bytes how many bytes need to be kept at this address
|
|
Packit |
875988 |
* @param new_size how many bytes should the allocation we return have?
|
|
Packit |
875988 |
* (should be larger or equal to @a copy_bytes)
|
|
Packit |
875988 |
* @return addr new address of @a keep (if it had to change)
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
void *
|
|
Packit |
875988 |
MHD_pool_reset (struct MemoryPool *pool,
|
|
Packit |
875988 |
void *keep,
|
|
Packit |
875988 |
size_t copy_bytes,
|
|
Packit |
875988 |
size_t new_size)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if ( (NULL != keep) &&
|
|
Packit |
875988 |
(keep != pool->memory) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (0 != copy_bytes)
|
|
Packit |
875988 |
memmove (pool->memory,
|
|
Packit |
875988 |
keep,
|
|
Packit |
875988 |
copy_bytes);
|
|
Packit |
875988 |
keep = pool->memory;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
pool->end = pool->size;
|
|
Packit |
875988 |
/* technically not needed, but safer to zero out */
|
|
Packit |
875988 |
if (pool->size > copy_bytes)
|
|
Packit |
875988 |
memset (&pool->memory[copy_bytes],
|
|
Packit |
875988 |
0,
|
|
Packit |
875988 |
pool->size - copy_bytes);
|
|
Packit |
875988 |
if (NULL != keep)
|
|
Packit |
875988 |
pool->pos = ROUND_TO_ALIGN (new_size);
|
|
Packit |
875988 |
return keep;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* end of memorypool.c */
|