{
#if ZEND_MM_STORAGE
if (UNEXPECTED(heap->storage)) {
- void *ptr = heap->storage->chunk_alloc(heap->storage, size, alignment);
+ void *ptr = heap->storage->handlers.chunk_alloc(heap->storage, size, alignment);
ZEND_ASSERT(((zend_uintptr_t)((char*)ptr + (alignment-1)) & (alignment-1)) == (zend_uintptr_t)ptr);
return ptr;
}
{
#if ZEND_MM_STORAGE
if (UNEXPECTED(heap->storage)) {
- heap->storage->chunk_free(heap->storage, addr, size);
+ heap->storage->handlers.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)
+static int 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;
+ if (heap->storage->handlers.chunk_truncate) {
+ return heap->storage->handlers.chunk_truncate(heap->storage, addr, old_size, new_size);
+ } else {
+ return 0;
+ }
}
#endif
+#ifndef _WIN32
zend_mm_munmap((char*)addr + new_size, old_size - new_size);
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+static int zend_mm_chunk_extend(zend_mm_heap *heap, void *addr, size_t old_size, size_t new_size)
+{
+#if ZEND_MM_STORAGE
+ if (UNEXPECTED(heap->storage)) {
+ if (heap->storage->handlers.chunk_extend) {
+ return heap->storage->handlers.chunk_extend(heap->storage, addr, old_size, new_size);
+ } else {
+ return 0;
+ }
+ }
+#endif
+#ifndef _WIN32
+ return (zend_mm_mmap_fixed((char*)addr + old_size, new_size - old_size) != NULL);
+#else
+ return 0;
+#endif
}
static zend_always_inline void zend_mm_chunk_init(zend_mm_heap *heap, zend_mm_chunk *chunk)
zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
return ptr;
-#ifndef _WIN32
} else if (new_size < old_size) {
/* unmup tail */
- zend_mm_chunk_truncate(heap, ptr, old_size, new_size);
+ if (zend_mm_chunk_truncate(heap, ptr, old_size, new_size)) {
#if ZEND_MM_STAT || ZEND_MM_LIMIT
- heap->real_size -= old_size - new_size;
+ heap->real_size -= old_size - new_size;
#endif
#if ZEND_MM_STAT
- heap->size -= old_size - new_size;
+ heap->size -= old_size - new_size;
#endif
#if ZEND_DEBUG
- zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
+ zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#else
- zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
+ zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
- return ptr;
+ return ptr;
+ }
} else /* if (new_size > old_size) */ {
#if ZEND_MM_LIMIT
if (heap->real_size + (new_size - old_size) > heap->limit) {
}
#endif
/* try to map tail right after this block */
- if (zend_mm_mmap_fixed((char*)ptr + old_size, new_size - old_size)) {
+ if (zend_mm_chunk_extend(heap, ptr, old_size, new_size)) {
#if ZEND_MM_STAT || ZEND_MM_LIMIT
heap->real_size += new_size - old_size;
#endif
#endif
return ptr;
}
-#endif
}
}
} else {
zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
}
/* free the first chunk */
-#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;
ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
{
-#if ZEND_MM_CUSTOM
+#if ZEND_MM_STORAGE
return heap->storage;
#else
return NULL
return zend_mm_init();
}
-ZEND_API zend_mm_heap *zend_mm_startup_ex(zend_mm_storage *storage)
+ZEND_API zend_mm_heap *zend_mm_startup_ex(zend_mm_handlers *handlers, void *data, size_t data_size)
{
#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_storage tmp_storage, *storage;
+ zend_mm_chunk *chunk;
zend_mm_heap *heap;
+ memcpy((zend_mm_handlers*)&tmp_storage.handlers, handlers, sizeof(zend_mm_handlers));
+ tmp_storage.data = data;
+ chunk = (zend_mm_chunk*)handlers->chunk_alloc(&tmp_storage, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
if (UNEXPECTED(chunk == NULL)) {
#if ZEND_MM_ERROR
#ifdef _WIN32
#if ZEND_MM_CUSTOM
heap->use_custom_heap = 0;
#endif
- heap->storage = storage;
+ heap->storage = &tmp_storage;
heap->huge_list = NULL;
+ storage = _zend_mm_alloc(heap, sizeof(zend_mm_storage) + data_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_CC);
+ if (!storage) {
+ handlers->chunk_free(&tmp_storage, chunk, ZEND_MM_CHUNK_SIZE);
+#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;
+ }
+ memcpy(storage, &tmp_storage, sizeof(zend_mm_storage));
+ if (data) {
+ storage->data = (void*)(((char*)storage + sizeof(zend_mm_storage)));
+ memcpy(storage->data, data, data_size);
+ }
+ heap->storage = storage;
return heap;
#else
return NULL;
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);
+typedef int (*zend_mm_chunk_truncate_t)(zend_mm_storage *storage, void *chunk, size_t old_size, size_t new_size);
+typedef int (*zend_mm_chunk_extend_t)(zend_mm_storage *storage, void *chunk, size_t old_size, size_t new_size);
-struct _zend_mm_storage {
+typedef struct _zend_mm_handlers {
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_mm_chunk_extend_t chunk_extend;
+} zend_mm_handlers;
+
+struct _zend_mm_storage {
+ const zend_mm_handlers handlers;
+ void *data;
};
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);
+ZEND_API zend_mm_heap *zend_mm_startup_ex(zend_mm_handlers *handlers, void *data, size_t data_size);
+
+/*
+
+// The following example shows how to use zend_mm_heap API with custom storage
+
+static zend_mm_heap *apc_heap = NULL;
+static HashTable *apc_ht = NULL;
+
+typedef struct _apc_data {
+ void *mem;
+ uint32_t free_pages;
+} apc_data;
+
+static void *apc_chunk_alloc(zend_mm_storage *storage, size_t size, size_t alignment)
+{
+ apc_data *data = (apc_data*)(storage->data);
+ size_t real_size = ((size + (ZEND_MM_CHUNK_SIZE-1)) & ~(ZEND_MM_CHUNK_SIZE-1));
+ uint32_t count = real_size / ZEND_MM_CHUNK_SIZE;
+ uint32_t first, last, i;
+
+ ZEND_ASSERT(alignment == ZEND_MM_CHUNK_SIZE);
+
+ for (first = 0; first < 32; first++) {
+ if (!(data->free_pages & (1 << first))) {
+ last = first;
+ do {
+ if (last - first == count - 1) {
+ for (i = first; i <= last; i++) {
+ data->free_pages |= (1 << i);
+ }
+ return (void *)(((char*)(data->mem)) + ZEND_MM_CHUNK_SIZE * (1 << first));
+ }
+ last++;
+ } while (last < 32 && !(data->free_pages & (1 << last)));
+ first = last;
+ }
+ }
+ return NULL;
+}
+
+static void apc_chunk_free(zend_mm_storage *storage, void *chunk, size_t size)
+{
+ apc_data *data = (apc_data*)(storage->data);
+ uint32_t i;
+
+ ZEND_ASSERT(((uintptr_t)chunk & (ZEND_MM_CHUNK_SIZE - 1)) == 0);
+
+ i = ((uintptr_t)chunk - (uintptr_t)(data->mem)) / ZEND_MM_CHUNK_SIZE;
+ while (1) {
+ data->free_pages &= ~(1 << i);
+ if (size <= ZEND_MM_CHUNK_SIZE) {
+ break;
+ }
+ size -= ZEND_MM_CHUNK_SIZE;
+ }
+}
+
+static void apc_init_heap(void)
+{
+ zend_mm_handlers apc_handlers = {
+ apc_chunk_alloc,
+ apc_chunk_free,
+ NULL,
+ NULL,
+ };
+ apc_data tmp_data;
+ zend_mm_heap *old_heap;
+
+ // Preallocate properly aligned SHM chunks (64MB)
+ tmp_data.mem = shm_memalign(ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE * 32);
+
+ // Initialize temporary storage data
+ tmp_data.free_pages = 0;
+
+ // Create heap
+ apc_heap = zend_mm_startup_ex(&apc_handlers, &tmp_data, sizeof(tmp_data));
+
+ // Allocate some data in the heap
+ old_heap = zend_mm_set_heap(apc_heap);
+ ALLOC_HASHTABLE(apc_ht);
+ zend_hash_init(apc_ht, 64, NULL, ZVAL_PTR_DTOR, 0);
+ zend_mm_set_heap(old_heap);
+}
+
+*/
END_EXTERN_C()