static void *vm_malloc_pages(VM *vm, size_t len, size_t alignment, int dirty_ok) { char *r; FreeBlock *blockfree = vm->freeblocks; if (!page_size) page_size = getpagesize(); /* Round up to nearest page: */ if (len & (page_size - 1)) len += page_size - (len & (page_size - 1)); /* Something from the cache, perhaps? */ r = alloc_cache_find_pages(blockfree, len, alignment, dirty_ok); if(!r) { /* attempt to allocate from OS */ r = os_vm_alloc_pages(len + alignment); if(r == (void *)-1) { return NULL; } if (alignment) { /* We allocated too large so we can choose the alignment. */ size_t extra = alignment; char *real_r = (char*)(((unsigned long)r + (alignment - 1)) & (~(alignment - 1))); long pre_extra = real_r - r; /* in front extra */ if (pre_extra) { os_vm_free_pages(r, pre_extra); } /* in back extra exists */ if (pre_extra < extra) { if (pre_extra == 0) { /* Instead of actually unmapping, put it in the cache, and there's a good chance we can use it next time: */ vm_memory_allocated_inc(vm, extra); alloc_cache_return_mem(vm, real_r + len, extra, 1); } else { os_vm_free_pages(real_r + len, extra - pre_extra); } } r = real_r; } vm_memory_allocated_inc(vm, len); } return r; }
static void *alloc_cache_alloc_page(AllocCacheBlock *blockfree, size_t len, size_t alignment, int dirty_ok, intptr_t *size_diff) { char *r; /* Something from the cache, perhaps? */ r = alloc_cache_find_pages(blockfree, len, alignment, dirty_ok); if(!r) { /* attempt to allocate from OS */ size_t extra = (alignment ? (alignment + CACHE_SEED_PAGES * APAGE_SIZE) : 0); r = os_alloc_pages(len + extra); if(r == (void *)-1) { return NULL; } if (alignment) { /* We allocated too large so we can choose the alignment. */ char *real_r = (char*)(((uintptr_t)r + (alignment - 1)) & (~(alignment - 1))); intptr_t pre_extra = real_r - r; /* in front extra */ if (pre_extra) { /* printf("FREEING FRONT %p %lx\n", r, pre_extra); */ os_free_pages(r, pre_extra); } /* in back extra exists */ if (pre_extra < extra) { if (pre_extra == 0) { /* Instead of actually unmapping, put it in the cache, and there's a good chance we can use it next time: */ (*size_diff) += extra; (*size_diff) += alloc_cache_free_page(blockfree, real_r + len, extra, 1, 1); } else { os_free_pages(real_r + len, extra - pre_extra); } } r = real_r; } (*size_diff) += len; } return r; }