diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:32:55 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:32:55 -0800 |
commit | dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0 (patch) | |
tree | 2ba8d1a0846d69b18f623515e8d9b5d9fe38b590 /libcutils/mspace.c | |
parent | e54eebbf1a908d65ee8cf80bab62821c05666d70 (diff) | |
download | core-dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0.tar.gz core-dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0.tar.bz2 core-dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0.zip |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'libcutils/mspace.c')
-rw-r--r-- | libcutils/mspace.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/libcutils/mspace.c b/libcutils/mspace.c new file mode 100644 index 000000000..8fd5de77d --- /dev/null +++ b/libcutils/mspace.c @@ -0,0 +1,246 @@ +/* Copyright 2006 The Android Open Source Project */ + +/* A wrapper file for dlmalloc.c that compiles in the + * mspace_*() functions, which provide an interface for + * creating multiple heaps. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/ioctl.h> + +#include <cutils/ashmem.h> + +/* It's a pain getting the mallinfo stuff to work + * with Linux, OSX, and klibc, so just turn it off + * for now. + * TODO: make mallinfo work + */ +#define NO_MALLINFO 1 + +/* Allow setting the maximum heap footprint. + */ +#define USE_MAX_ALLOWED_FOOTPRINT 1 + +/* Don't try to trim memory. + * TODO: support this. + */ +#define MORECORE_CANNOT_TRIM 1 + +/* Use mmap()d anonymous memory to guarantee + * that an mspace is contiguous. + * + * create_mspace() won't work right if this is + * defined, so hide the definition of it and + * break any users at build time. + */ +#define USE_CONTIGUOUS_MSPACES 1 +#if USE_CONTIGUOUS_MSPACES +/* This combination of settings forces sys_alloc() + * to always use MORECORE(). It won't expect the + * results to be contiguous, but we'll guarantee + * that they are. + */ +#define HAVE_MMAP 0 +#define HAVE_MORECORE 1 +#define MORECORE_CONTIGUOUS 0 +/* m is always the appropriate local when MORECORE() is called. */ +#define MORECORE(S) contiguous_mspace_morecore(m, S) +#define create_mspace HIDDEN_create_mspace_HIDDEN +#define destroy_mspace HIDDEN_destroy_mspace_HIDDEN +typedef struct malloc_state *mstate0; +static void *contiguous_mspace_morecore(mstate0 m, ssize_t nb); +#endif + +#define MSPACES 1 +#define ONLY_MSPACES 1 +#include "../../../bionic/libc/bionic/dlmalloc.c" + +#ifndef PAGESIZE +#define PAGESIZE mparams.page_size +#endif + +#define ALIGN_UP(p, alignment) \ + (((uintptr_t)(p) + (alignment)-1) & ~((alignment)-1)) + +/* A direct copy of dlmalloc_usable_size(), + * which isn't compiled in when ONLY_MSPACES is set. + * The mspace parameter isn't actually necessary, + * but we include it to be consistent with the + * rest of the mspace_*() functions. + */ +size_t mspace_usable_size(mspace _unused, const void* mem) { + if (mem != 0) { + const mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +#if USE_CONTIGUOUS_MSPACES +#include <sys/mman.h> +#include <limits.h> + +#define CONTIG_STATE_MAGIC 0xf00dd00d +struct mspace_contig_state { + unsigned int magic; + char *brk; + char *top; + mspace m; +}; + +static void *contiguous_mspace_morecore(mstate m, ssize_t nb) { + struct mspace_contig_state *cs; + char *oldbrk; + const unsigned int pagesize = PAGESIZE; + + cs = (struct mspace_contig_state *)((uintptr_t)m & ~(pagesize-1)); + assert(cs->magic == CONTIG_STATE_MAGIC); + assert(cs->m == m); +assert(nb >= 0); //xxx deal with the trim case + + oldbrk = cs->brk; + if (nb > 0) { + /* Break to the first page boundary that satisfies the request. + */ + char *newbrk = (char *)ALIGN_UP(oldbrk + nb, pagesize); + if (newbrk > cs->top) + return CMFAIL; + + /* Update the protection on the underlying memory. + * Pages we've given to dlmalloc are read/write, and + * pages we haven't are not accessable (read or write + * will cause a seg fault). + */ + if (mprotect(cs, newbrk - (char *)cs, PROT_READ | PROT_WRITE) < 0) + return CMFAIL; + if (newbrk != cs->top) { + if (mprotect(newbrk, cs->top - newbrk, PROT_NONE) < 0) + return CMFAIL; + } + + cs->brk = newbrk; + + /* Make sure that dlmalloc will merge this block with the + * initial block that was passed to create_mspace_with_base(). + * We don't care about extern vs. non-extern, so just clear it. + */ + m->seg.sflags &= ~EXTERN_BIT; + } + + return oldbrk; +} + +mspace create_contiguous_mspace_with_name(size_t starting_capacity, + size_t max_capacity, int locked, char const * name) { + int fd, ret; + struct mspace_contig_state *cs; + char buf[ASHMEM_NAME_LEN] = "mspace"; + void *base; + unsigned int pagesize; + mstate m; + + if (starting_capacity > max_capacity) + return (mspace)0; + + init_mparams(); + pagesize = PAGESIZE; + + /* Create the anonymous memory that will back the mspace. + * This reserves all of the virtual address space we could + * ever need. Physical pages will be mapped as the memory + * is touched. + * + * Align max_capacity to a whole page. + */ + max_capacity = (size_t)ALIGN_UP(max_capacity, pagesize); + + if (name) + snprintf(buf, sizeof(buf), "mspace/%s", name); + fd = ashmem_create_region(buf, max_capacity); + if (fd < 0) + return (mspace)0; + + base = mmap(NULL, max_capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + close(fd); + if (base == MAP_FAILED) + return (mspace)0; + + /* Make sure that base is at the beginning of a page. + */ + assert(((uintptr_t)base & (pagesize-1)) == 0); + + /* Reserve some space for the information that our MORECORE needs. + */ + cs = base; + + /* Create the mspace, pointing to the memory we just reserved. + */ + m = create_mspace_with_base(base + sizeof(*cs), starting_capacity, locked); + if (m == (mspace)0) + goto error; + + /* Make sure that m is in the same page as cs. + */ + assert(((uintptr_t)m & (uintptr_t)~(pagesize-1)) == (uintptr_t)base); + + /* Find out exactly how much of the memory the mspace + * is using. + */ + cs->brk = m->seg.base + m->seg.size; + cs->top = (char *)base + max_capacity; + assert((char *)base <= cs->brk); + assert(cs->brk <= cs->top); + + /* Prevent access to the memory we haven't handed out yet. + */ + if (cs->brk != cs->top) { + /* mprotect() requires page-aligned arguments, but it's possible + * for cs->brk not to be page-aligned at this point. + */ + char *prot_brk = (char *)ALIGN_UP(cs->brk, pagesize); + if (mprotect(prot_brk, cs->top - prot_brk, PROT_NONE) < 0) + goto error; + } + + cs->m = m; + cs->magic = CONTIG_STATE_MAGIC; + + return (mspace)m; + +error: + munmap(base, max_capacity); + return (mspace)0; +} + +mspace create_contiguous_mspace(size_t starting_capacity, + size_t max_capacity, int locked) { + return create_contiguous_mspace_with_name(starting_capacity, + max_capacity, locked, NULL); +} + +size_t destroy_contiguous_mspace(mspace msp) { + mstate ms = (mstate)msp; + + if (ok_magic(ms)) { + struct mspace_contig_state *cs; + size_t length; + const unsigned int pagesize = PAGESIZE; + + cs = (struct mspace_contig_state *)((uintptr_t)ms & ~(pagesize-1)); + assert(cs->magic == CONTIG_STATE_MAGIC); + assert(cs->m == ms); + + length = cs->top - (char *)cs; + if (munmap((char *)cs, length) != 0) + return length; + } + else { + USAGE_ERROR_ACTION(ms, ms); + } + return 0; +} +#endif |