]> granicus.if.org Git - php/commitdiff
Allow to substitute storage layer in memory manager.
authorDmitry Stogov <dmitry@zend.com>
Tue, 14 Oct 2014 05:41:16 +0000 (09:41 +0400)
committerDmitry Stogov <dmitry@zend.com>
Tue, 14 Oct 2014 05:41:16 +0000 (09:41 +0400)
Zend/zend_alloc.c
Zend/zend_alloc.h

index dd1c2d64503fee264eee68b9a34f8ce29d9ceadf..32d2e5f23463b43586852da25ac4d2697162c5a2 100644 (file)
 # 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)) {
@@ -1708,6 +1748,9 @@ zend_mm_heap *zend_mm_init(void)
 #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;
@@ -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
index 6d310cbca333a7b189c6a46e3539ed884e9036bc..d0226bd04d8f5fcaae3588872281ab58a188b755 100644 (file)
@@ -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