summaryrefslogtreecommitdiff
path: root/Zend/zend_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_alloc.c')
-rw-r--r--Zend/zend_alloc.c173
1 files changed, 159 insertions, 14 deletions
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index aea04d82f0..fb4d3b35e1 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -119,6 +119,9 @@
# 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
@@ -217,6 +220,9 @@ struct _zend_mm_heap {
#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 */
@@ -707,7 +713,7 @@ static zend_always_inline int zend_mm_bitset_is_free_range(zend_mm_bitset *bitse
/* 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);
@@ -751,6 +757,40 @@ static void *zend_mm_chunk_alloc(size_t size, size_t alignment)
}
}
+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;
@@ -928,7 +968,7 @@ not_found:
}
}
#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
@@ -1019,11 +1059,11 @@ static void zend_mm_free_pages(zend_mm_heap *heap, zend_mm_chunk *chunk, int pag
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;
}
}
@@ -1355,7 +1395,7 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size ZEN
#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
@@ -1607,7 +1647,7 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D
}
}
#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
@@ -1649,7 +1689,7 @@ static void zend_mm_free_huge(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZE
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
@@ -1662,9 +1702,9 @@ static void zend_mm_free_huge(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZE
/* 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)) {
@@ -1707,6 +1747,9 @@ zend_mm_heap *zend_mm_init(void)
#if ZEND_MM_CUSTOM
heap->use_custom_heap = 0;
#endif
+#if ZEND_MM_STORAGE
+ heap->storage = NULL;
+#endif
heap->huge_list = NULL;
return heap;
}
@@ -1805,7 +1848,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap TSRMLS_DC)
}
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);
}
@@ -1904,7 +1947,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent TSRMLS_DC)
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 */
@@ -1923,10 +1966,20 @@ void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent TSRMLS_DC)
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;
@@ -1936,7 +1989,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent TSRMLS_DC)
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 */
@@ -2343,6 +2396,98 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
#endif
}
+ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
+ void* (**_malloc)(size_t),
+ void (**_free)(void*),
+ void* (**_realloc)(void*, size_t))
+{
+#if ZEND_MM_CUSTOM
+ zend_mm_heap *_heap = (zend_mm_heap*)heap;
+
+ if (heap->use_custom_heap) {
+ *_malloc = _heap->_malloc;
+ *_free = _heap->_free;
+ *_realloc = _heap->_realloc;
+ } else {
+ *_malloc = NULL;
+ *_free = NULL;
+ *_realloc = NULL;
+ }
+#else
+ *_malloc = NULL;
+ *_free = NULL;
+ *_realloc = NULL;
+#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