# define ZEND_MM_CUSTOM 1 /* support for custom memory allocator */
/* USE_ZEND_ALLOC=0 may switch to system malloc() */
#endif
+#ifndef ZEND_MM_STORAGE
+# define ZEND_MM_STORAGE 1 /* support for custom memory storage */
+#endif
#ifndef ZEND_MM_ERROR
# define ZEND_MM_ERROR 1 /* report system errors */
#endif
#if ZEND_MM_CUSTOM
int use_custom_heap;
#endif
+#if ZEND_MM_STORAGE
+ zend_mm_storage *storage;
+#endif
#if ZEND_MM_STAT
size_t size; /* current memory usage */
size_t peak; /* peak memory usage */
/* Chunks */
/**********/
-static void *zend_mm_chunk_alloc(size_t size, size_t alignment)
+static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment)
{
void *ptr = zend_mm_mmap(size);
}
}
+static void *zend_mm_chunk_alloc(zend_mm_heap *heap, size_t size, size_t alignment)
+{
+#if ZEND_MM_STORAGE
+ if (UNEXPECTED(heap->storage)) {
+ void *ptr = heap->storage->chunk_alloc(heap->storage, size, alignment);
+ ZEND_ASSERT(((zend_uintptr_t)((char*)ptr + (alignment-1)) & (alignment-1)) == (zend_uintptr_t)ptr);
+ return ptr;
+ }
+#endif
+ return zend_mm_chunk_alloc_int(size, alignment);
+}
+
+static void zend_mm_chunk_free(zend_mm_heap *heap, void *addr, size_t size)
+{
+#if ZEND_MM_STORAGE
+ if (UNEXPECTED(heap->storage)) {
+ heap->storage->chunk_free(heap->storage, addr, size);
+ return;
+ }
+#endif
+ zend_mm_munmap(addr, size);
+}
+
+static void zend_mm_chunk_truncate(zend_mm_heap *heap, void *addr, size_t old_size, size_t new_size)
+{
+#if ZEND_MM_STORAGE
+ if (UNEXPECTED(heap->storage)) {
+ heap->storage->chunk_truncate(heap->storage, addr, old_size, new_size);
+ return;
+ }
+#endif
+ zend_mm_munmap((char*)addr + new_size, old_size - new_size);
+}
+
static zend_always_inline void zend_mm_chunk_init(zend_mm_heap *heap, zend_mm_chunk *chunk)
{
chunk->heap = heap;
}
}
#endif
- chunk = (zend_mm_chunk*)zend_mm_chunk_alloc(ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
+ chunk = (zend_mm_chunk*)zend_mm_chunk_alloc(heap, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
if (UNEXPECTED(chunk == NULL)) {
/* insufficient memory */
#if !ZEND_MM_LIMIT
heap->real_size -= ZEND_MM_CHUNK_SIZE;
#endif
if (!heap->cached_chunks || chunk->num > heap->cached_chunks->num) {
- zend_mm_munmap(chunk, ZEND_MM_CHUNK_SIZE);
+ zend_mm_chunk_free(heap, chunk, ZEND_MM_CHUNK_SIZE);
} else {
//TODO: select the best chunk to delete???
chunk->next = heap->cached_chunks->next;
- zend_mm_munmap(heap->cached_chunks, ZEND_MM_CHUNK_SIZE);
+ zend_mm_chunk_free(heap, heap->cached_chunks, ZEND_MM_CHUNK_SIZE);
heap->cached_chunks = chunk;
}
}
#ifndef _WIN32
} else if (new_size < old_size) {
/* unmup tail */
- zend_mm_munmap((char*)ptr + new_size, old_size - new_size);
+ zend_mm_chunk_truncate(heap, ptr, old_size, new_size);
#if ZEND_MM_STAT || ZEND_MM_LIMIT
heap->real_size -= old_size - new_size;
#endif
}
}
#endif
- ptr = zend_mm_chunk_alloc(new_size, ZEND_MM_CHUNK_SIZE);
+ ptr = zend_mm_chunk_alloc(heap, new_size, ZEND_MM_CHUNK_SIZE);
if (UNEXPECTED(ptr == NULL)) {
/* insufficient memory */
#if !ZEND_MM_LIMIT
ZEND_MM_CHECK(ZEND_MM_ALIGNED_OFFSET(ptr, ZEND_MM_CHUNK_SIZE) == 0, "zend_mm_heap corrupted");
size = zend_mm_del_huge_block(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
- zend_mm_munmap(ptr, size);
+ zend_mm_chunk_free(heap, ptr, size);
#if ZEND_MM_STAT || ZEND_MM_LIMIT
heap->real_size -= size;
#endif
/* Initialization */
/******************/
-zend_mm_heap *zend_mm_init(void)
+static zend_mm_heap *zend_mm_init(void)
{
- zend_mm_chunk *chunk = (zend_mm_chunk*)zend_mm_chunk_alloc(ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
+ zend_mm_chunk *chunk = (zend_mm_chunk*)zend_mm_chunk_alloc_int(ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
zend_mm_heap *heap;
if (UNEXPECTED(chunk == NULL)) {
#endif
#if ZEND_MM_CUSTOM
heap->use_custom_heap = 0;
+#endif
+#if ZEND_MM_STORAGE
+ heap->storage = NULL;
#endif
heap->huge_list = NULL;
return heap;
}
list = list->next;
- zend_mm_munmap(q->ptr, q->size);
+ zend_mm_chunk_free(heap, q->ptr, q->size);
zend_mm_free_heap(heap, q, NULL, 0, NULL, 0);
}
while (list) {
zend_mm_huge_list *q = list;
list = list->next;
- zend_mm_munmap(q->ptr, q->size);
+ zend_mm_chunk_free(heap, q->ptr, q->size);
}
/* move all chunks except of the first one into the cache */
while (heap->cached_chunks) {
p = heap->cached_chunks;
heap->cached_chunks = p->next;
- zend_mm_munmap(p, ZEND_MM_CHUNK_SIZE);
+ zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
}
/* free the first chunk */
- zend_mm_munmap(heap->main_chunk, ZEND_MM_CHUNK_SIZE);
+#if ZEND_MM_STORAGE
+ if (UNEXPECTED(heap->storage)) {
+ zend_mm_storage *storage = heap->storage;
+ zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
+ storage->dtor(storage);
+ } else {
+ zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
+ }
+#else
+ zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
+#endif
} else {
zend_mm_heap old_heap;
heap->cached_chunks) {
p = heap->cached_chunks;
heap->cached_chunks = p->next;
- zend_mm_munmap(p, ZEND_MM_CHUNK_SIZE);
+ zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
heap->cached_chunks_count--;
}
/* clear cached chunks */
#endif
}
+ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
+{
+#if ZEND_MM_CUSTOM
+ return heap->storage;
+#else
+ return NULL
+#endif
+}
+
+ZEND_API zend_mm_heap *zend_mm_startup(void)
+{
+ return zend_mm_init();
+}
+
+ZEND_API zend_mm_heap *zend_mm_startup_ex(zend_mm_storage *storage)
+{
+#if ZEND_MM_STORAGE
+ zend_mm_chunk *chunk = (zend_mm_chunk*)storage->chunk_alloc(storage, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
+ zend_mm_heap *heap;
+
+ if (UNEXPECTED(chunk == NULL)) {
+#if ZEND_MM_ERROR
+#ifdef _WIN32
+ stderr_last_error("Can't initialize heap");
+#else
+ fprintf(stderr, "\nCan't initialize heap: [%d] %s\n", errno, strerror(errno));
+#endif
+#endif
+ return NULL;
+ }
+ heap = &chunk->heap_slot;
+ chunk->heap = heap;
+ chunk->next = chunk;
+ chunk->prev = chunk;
+ chunk->free_pages = ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE;
+ chunk->free_tail = ZEND_MM_FIRST_PAGE;
+ chunk->num = 0;
+ chunk->free_map[0] = (Z_L(1) << ZEND_MM_FIRST_PAGE) - 1;
+ chunk->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE);
+ heap->main_chunk = chunk;
+ heap->cached_chunks = NULL;
+ heap->chunks_count = 1;
+ heap->peak_chunks_count = 1;
+ heap->cached_chunks_count = 0;
+ heap->avg_chunks_count = 1.0;
+#if ZEND_MM_STAT || ZEND_MM_LIMIT
+ heap->real_size = ZEND_MM_CHUNK_SIZE;
+#endif
+#if ZEND_MM_STAT
+ heap->real_peak = ZEND_MM_CHUNK_SIZE;
+ heap->size = 0;
+ heap->peak = 0;
+#endif
+#if ZEND_MM_LIMIT
+ heap->limit = (Z_L(-1) >> Z_L(1));
+ heap->overflow = 0;
+#endif
+#if ZEND_MM_CUSTOM
+ heap->use_custom_heap = 0;
+#endif
+ heap->storage = storage;
+ heap->huge_list = NULL;
+ return heap;
+#else
+ return NULL;
+#endif
+}
+
/*
* Local variables:
* tab-width: 4