Created
October 13, 2014 14:44
-
-
Save dstogov/a3fa612c33d4809a7393 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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