[dovecot-cvs] dovecot/src/lib mmap-anon.c,1.7,1.8
cras at procontrol.fi
cras at procontrol.fi
Fri Dec 27 17:39:12 EET 2002
- Previous message: [dovecot-cvs] dovecot/src/lib data-stack.c,1.14,1.15 mempool-alloconly.c,1.14,1.15 mempool-datastack.c,1.3,1.4 mempool-system.c,1.6,1.7 mempool.h,1.6,1.7
- Next message: [dovecot-cvs] dovecot configure.in,1.78,1.79
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /home/cvs/dovecot/src/lib
In directory danu:/tmp/cvs-serv24229/lib
Modified Files:
mmap-anon.c
Log Message:
Old implementation was overly complex and stupid.
Index: mmap-anon.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/mmap-anon.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- mmap-anon.c 18 Dec 2002 15:15:41 -0000 1.7
+++ mmap-anon.c 27 Dec 2002 15:39:10 -0000 1.8
@@ -45,37 +45,31 @@
# define MMAP_BASE_MOVE (1024UL*1024UL*128UL) /* 128M */
#endif
-/* get it near 4kB which is the most common page size */
-#define MAX_CHUNKS (4096 / 2 / sizeof(size_t) - 3)
-
#define MMAP_SIGNATURE 0xdeadbeef
#define PAGE_ALIGN(size) \
- (((size) + page_size) & ~(size_t)(page_size-1))
+ (((size) + (size_t)page_size-1) & ~(size_t)(page_size-1))
struct movable_header {
unsigned int signature;
- int chunks;
size_t size;
-
- void *chunk_ptr[MAX_CHUNKS];
- size_t chunk_size[MAX_CHUNKS];
};
static int page_size = 0;
static int header_size = 0;
static void *movable_mmap_base = NULL;
+static void *mmap_top_limit = NULL;
static void movable_mmap_init(void)
{
+ char x;
+
page_size = getpagesize();
+ header_size = page_size;
- if (page_size >= header_size)
- header_size = page_size;
- else {
- header_size = sizeof(struct movable_header) + page_size -
- sizeof(struct movable_header) % page_size;
- }
+ /* keep our allocations far below stack. assumes the stack is
+ growing down. */
+ mmap_top_limit = &x - (1024*1024*256);
}
static int anon_mmap_fixed(void *address, size_t length)
@@ -113,6 +107,8 @@
void *mmap_anon(size_t length)
{
struct movable_header *hdr;
+ void *next_mmap_base;
+ ssize_t offset;
int ret;
if (header_size == 0)
@@ -120,8 +116,7 @@
/* we need extra page to store the pieces which construct
the full mmap. also allocate only page-aligned mmap sizes. */
- length += header_size;
- length = PAGE_ALIGN(length);
+ length = PAGE_ALIGN(length + header_size);
if (movable_mmap_base == NULL) {
/* this is fully guessing */
@@ -129,131 +124,111 @@
PAGE_ALIGN((size_t)((char *)mmap_anon - (char *)NULL));
}
- do {
- movable_mmap_base = (char *) movable_mmap_base +
- MMAP_BASE_MOVE;
- hdr = movable_mmap_base;
+ offset = MMAP_BASE_MOVE;
+ for (;;) {
+ next_mmap_base = (char *) movable_mmap_base + offset;
+ if ((char *) next_mmap_base < (char *) movable_mmap_base) {
+ /* we're wrapping, fix the offset a bit so we won't
+ just loop with same addresses.. */
+ offset /= 2;
+ if (offset/10 < page_size) {
+ /* enough tries */
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+ }
- if (movable_mmap_base != NULL)
- ret = anon_mmap_fixed(movable_mmap_base, length);
- else {
- /* we can't use NULL address */
- errno = EINVAL;
- ret = -1;
+ movable_mmap_base = next_mmap_base;
+
+ if ((char *) movable_mmap_base >
+ (char *) movable_mmap_base + length) {
+ /* too high, would wrap */
+ continue;
}
- } while (ret == -1 && errno == EINVAL);
+ if ((char *) movable_mmap_base + length >=
+ (char *) mmap_top_limit) {
+ /* too high, stack could grow over it */
+ continue;
+ }
- if (ret == -1)
- return MAP_FAILED;
+ if (movable_mmap_base == NULL)
+ continue;
+
+ ret = anon_mmap_fixed(movable_mmap_base, length);
+ if (ret == 0)
+ break;
+
+ if (ret < 0 && errno != EINVAL)
+ return MAP_FAILED;
+ }
/* initialize the header */
+ hdr = movable_mmap_base;
hdr->signature = MMAP_SIGNATURE;
- hdr->chunks = 1;
- hdr->size = length;
- hdr->chunk_ptr[0] = hdr;
- hdr->chunk_size[0] = length;
+ hdr->size = length - header_size;
return (char *) hdr + header_size;
}
-static void *remove_chunks(struct movable_header *hdr, size_t new_size)
+static int mremap_try_grow(struct movable_header *hdr, size_t new_size)
{
- int i;
+ void *grow_base;
- for (i = hdr->chunks-1; i > 0; i--) {
- if (hdr->size - hdr->chunk_size[i] < new_size)
- break;
+ grow_base = (char *) hdr + header_size + hdr->size;
+ if ((char *) grow_base <= (char *) hdr + header_size ||
+ (char *) grow_base >= (char *) mmap_top_limit) {
+ /* overflows valid address range */
+ return 0;
+ }
- if (munmap(hdr->chunk_ptr[i], hdr->chunk_size[i]) < 0)
- i_panic("munmap() failed: %m");
+ if (anon_mmap_fixed(grow_base, new_size - hdr->size) < 0) {
+ if (errno == EINVAL) {
+ /* can't grow, wanted address space is already in use */
+ return 0;
+ }
- hdr->size -= hdr->chunk_size[i];
- hdr->chunks--;
+ return -1;
}
- return (char *) hdr + header_size;
+ hdr->size = new_size;
+ return 1;
}
-static void *move_chunks(struct movable_header *hdr, size_t new_size,
- int maymove)
+static void *mremap_move(struct movable_header *hdr, size_t new_size)
{
- unsigned char *new_base, *p;
- int i;
-
- if (!maymove) {
- errno = ENOMEM;
- return MAP_FAILED;
- }
+ void *new_base;
+ char *p;
+ size_t block_size, old_size;
new_base = mmap_anon(new_size - header_size);
if (new_base == MAP_FAILED)
return MAP_FAILED;
- /* copy first chunk without header */
- memcpy(new_base, (char *) hdr->chunk_ptr[0] + header_size,
- hdr->chunk_size[0] - header_size);
- p = new_base + (hdr->chunk_size[0] - header_size);
+ /* If we're moving large memory areas, it takes less memory to
+ copy the memory pages in smaller blocks. */
+ old_size = hdr->size;
+ block_size = 1024*1024;
- for (i = 1; i < hdr->chunks; i++) {
- memcpy(p, hdr->chunk_ptr[i], hdr->chunk_size[i]);
- p += hdr->chunk_size[i];
+ p = (char *) (hdr + header_size + hdr->size);
+ do {
+ if (block_size > old_size)
+ block_size = old_size;
+ p -= block_size;
- if (munmap(hdr->chunk_ptr[i], hdr->chunk_size[i]) < 0)
+ memcpy((char *) new_base + (p - (char *) hdr), p, block_size);
+ if (munmap(p, block_size) < 0)
i_panic("munmap() failed: %m");
- }
+ } while (p != (char *) hdr);
- if (munmap(hdr->chunk_ptr[0], hdr->chunk_size[0]) < 0)
- i_panic("munmap() failed: %m");
return new_base;
}
-static void *add_chunks(struct movable_header *hdr, size_t new_size,
- int maymove)
-{
- void *base;
- size_t chunk_size;
-
- new_size = PAGE_ALIGN(new_size);
- if (hdr->chunks == MAX_CHUNKS)
- return move_chunks(hdr, new_size, maymove);
-
- /* get our new address, make sure we're not over/underflowing
- our address */
-#if MMAP_BASE_MOVE > 0
- base = (char *) hdr->chunk_ptr[hdr->chunks-1] +
- hdr->chunk_size[hdr->chunks-1];
- if (base < hdr->chunk_ptr[hdr->chunks-1])
- return move_chunks(hdr, new_size, maymove);
-#else
- base = (char *) hdr->chunk_ptr[hdr->chunks-1] -
- hdr->chunk_size[hdr->chunks-1];
- if (base > hdr->chunk_ptr[hdr->chunks-1])
- return move_chunks(hdr, new_size, maymove);
-#endif
-
- chunk_size = new_size - hdr->size;
- if (anon_mmap_fixed(base, chunk_size) < 0) {
- if (errno == EINVAL) {
- /* can't grow, the memory address is used */
- return move_chunks(hdr, new_size, maymove);
- }
-
- return MAP_FAILED;
- }
-
- hdr->chunk_ptr[hdr->chunks] = base;
- hdr->chunk_size[hdr->chunks] = chunk_size;
- hdr->size += chunk_size;
- hdr->chunks++;
-
- return (char *) hdr + header_size;
-}
-
void *mremap_anon(void *old_address, size_t old_size __attr_unused__,
size_t new_size, unsigned long flags)
{
struct movable_header *hdr;
+ int ret;
if (old_address == NULL || old_address == MAP_FAILED) {
errno = EINVAL;
@@ -264,18 +239,38 @@
if (hdr->signature != MMAP_SIGNATURE)
i_panic("movable_mremap(): Invalid old_address");
- new_size += header_size;
+ new_size = PAGE_ALIGN(new_size);
- if (hdr->size > new_size)
- return remove_chunks(hdr, new_size);
- else
- return add_chunks(hdr, new_size, (flags & MREMAP_MAYMOVE) != 0);
+ if (new_size > hdr->size) {
+ /* grow */
+ ret = mremap_try_grow(hdr, new_size);
+ if (ret > 0)
+ return old_address;
+ if (ret < 0)
+ return MAP_FAILED;
+
+ if ((flags & MREMAP_MAYMOVE) == 0) {
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+
+ return mremap_move(hdr, new_size);
+ }
+
+ if (new_size < hdr->size) {
+ /* shrink */
+ if (munmap((char *) hdr + header_size + new_size,
+ hdr->size - new_size) < 0)
+ i_panic("munmap() failed: %m");
+ hdr->size = new_size;
+ }
+
+ return old_address;
}
int munmap_anon(void *start, size_t length __attr_unused__)
{
struct movable_header *hdr;
- int i;
if (start == NULL || start == MAP_FAILED) {
errno = EINVAL;
@@ -286,11 +281,8 @@
if (hdr->signature != MMAP_SIGNATURE)
i_panic("movable_munmap(): Invalid address");
- /* [0] chunk must be free'd last since it contains the header */
- for (i = hdr->chunks-1; i >= 0; i--) {
- if (munmap(hdr->chunk_ptr[i], hdr->chunk_size[i]) < 0)
- i_panic("munmap() failed: %m");
- }
+ if (munmap(hdr, hdr->size + header_size) < 0)
+ i_panic("munmap() failed: %m");
return 0;
}
- Previous message: [dovecot-cvs] dovecot/src/lib data-stack.c,1.14,1.15 mempool-alloconly.c,1.14,1.15 mempool-datastack.c,1.3,1.4 mempool-system.c,1.6,1.7 mempool.h,1.6,1.7
- Next message: [dovecot-cvs] dovecot configure.in,1.78,1.79
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the dovecot-cvs
mailing list