Skip to content

Instantly share code, notes, and snippets.

@dstogov
Created October 13, 2014 14:44
Show Gist options
  • Save dstogov/a3fa612c33d4809a7393 to your computer and use it in GitHub Desktop.
Save dstogov/a3fa612c33d4809a7393 to your computer and use it in GitHub Desktop.
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index dd1c2d6..32d2e5f 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 */
@@ -709,7 +715,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);
@@ -753,6 +759,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;
@@ -930,7 +970,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
@@ -1021,11 +1061,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;
}
}
@@ -1357,7 +1397,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
@@ -1609,7 +1649,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
@@ -1651,7 +1691,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
@@ -1664,9 +1704,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)) {
@@ -1709,6 +1749,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;
}
@@ -1807,7 +1850,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);
}
@@ -1906,7 +1949,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 */
@@ -1925,10 +1968,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;
@@ -1938,7 +1991,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 */
@@ -2370,6 +2423,74 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
#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
diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h
index 6d310cb..d0226bd 100644
--- a/Zend/zend_alloc.h
+++ b/Zend/zend_alloc.h
@@ -260,6 +260,23 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
void (*_free)(void*),
void* (*_realloc)(void*, size_t));
+typedef struct _zend_mm_storage zend_mm_storage;
+
+typedef void* (*zend_mm_chunk_alloc_t)(zend_mm_storage *storage, size_t size, size_t alignment);
+typedef void (*zend_mm_chunk_free_t)(zend_mm_storage *storage, void *chunk, size_t size);
+typedef void (*zend_mm_chunk_truncate_t)(zend_mm_storage *storage, void *chunk, size_t old_size, size_t new_size);
+typedef void (*zend_mm_storage_dtor_t)(zend_mm_storage *storage);
+
+struct _zend_mm_storage {
+ zend_mm_chunk_alloc_t chunk_alloc;
+ zend_mm_chunk_free_t chunk_free;
+ zend_mm_chunk_truncate_t chunk_truncate;
+ zend_mm_storage_dtor_t dtor;
+};
+
+ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap);
+ZEND_API zend_mm_heap *zend_mm_startup_ex(zend_mm_storage *storage);
+
END_EXTERN_C()
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment