From 42efedb79369a6241455357b54b2b385b70b0e72 Mon Sep 17 00:00:00 2001 From: Xuefer Date: Sat, 9 Sep 2006 00:56:44 +0000 Subject: [PATCH] reconstruct shm/allocator git-svn-id: svn://svn.lighttpd.net/xcache/trunk@148 c26eb9a1-5813-0410-bd6c-c2e55f420ca7 --- Makefile.frag | 4 +- config.m4 | 2 + config.w32 | 2 + mem.c | 80 +++++++++++++---- mem.h | 74 +++++++++++++--- mmap.c | 59 +++++++++---- myshm.h | 13 --- processor/head.m4 | 2 +- processor/main.m4 | 4 +- utils.c | 2 - xc_malloc.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++ xc_shm.c | 76 +++++++++++++++++ xc_shm.h | 60 +++++++++++++ xcache.c | 86 ++++++++++++------- xcache.h | 3 +- 15 files changed, 578 insertions(+), 101 deletions(-) delete mode 100644 myshm.h create mode 100644 xc_malloc.c create mode 100644 xc_shm.c create mode 100644 xc_shm.h diff --git a/Makefile.frag b/Makefile.frag index 120db89..8ed93be 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -31,8 +31,8 @@ processor.lo: $(XCACHE_PROC_C) $(XCACHE_PROC_H) $(srcdir)/processor.c $(builddir)/disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c -$(builddir)/xcache.lo: $(XCACHE_PROC_H) $(srcdir)/myshm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c $(srcdir)/foreachcoresig.h -xcache.lo: $(XCACHE_PROC_H) $(srcdir)/myshm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c $(srcdir)/foreachcoresig.h +$(builddir)/xcache.lo: $(XCACHE_PROC_H) $(srcdir)/xc_shm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c $(srcdir)/foreachcoresig.h +xcache.lo: $(XCACHE_PROC_H) $(srcdir)/xc_shm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c $(srcdir)/foreachcoresig.h xcachesvnclean: clean cat $(srcdir)/.cvsignore | grep -v Makefile | xargs rm -f diff --git a/config.m4 b/config.m4 index a33dddb..091009b 100644 --- a/config.m4 +++ b/config.m4 @@ -27,6 +27,8 @@ if test "$PHP_XCACHE" != "no"; then xcache.c \ mmap.c \ mem.c \ + xc_malloc.c \ + xc_shm.c \ const_string.c \ opcode_spec.c \ stack.c \ diff --git a/config.w32 b/config.w32 index 6171755..ed13431 100644 --- a/config.w32 +++ b/config.w32 @@ -15,6 +15,8 @@ if (PHP_XCACHE != "no") { xcache.c \ mmap.c \ mem.c \ + xc_malloc.c \ + xc_shm.c \ const_string.c \ opcode_spec.c \ stack.c \ diff --git a/mem.c b/mem.c index faded80..1257b98 100644 --- a/mem.c +++ b/mem.c @@ -8,7 +8,9 @@ #include #include #include -#include "mem.h" +#define XC_SHM_IMPL +#define XC_MEM_IMPL +#include "xc_shm.h" #include "align.h" #ifdef TEST @@ -36,6 +38,8 @@ struct _xc_block_t { }; struct _xc_mem_t { + const xc_mem_handlers_t *handlers; + xc_shm_t *shm; xc_memsize_t size; xc_memsize_t avail; /* total free */ xc_block_t headblock[1]; /* just as a pointer to first block*/ @@ -74,7 +78,7 @@ static void xc_block_check(xc_block_t *b) /* {{{ */ #endif -void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size) /* {{{ */ +static XC_MEM_MALLOC(xc_mem_malloc) /* {{{ */ { xc_block_t *prev, *cur; xc_block_t *newb, *b; @@ -182,7 +186,7 @@ void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size) /* {{{ */ return p; } /* }}} */ -int xc_mem_free(xc_mem_t *mem, const void *p) /* {{{ return block size freed */ +static XC_MEM_FREE(xc_mem_free) /* {{{ return block size freed */ { xc_block_t *cur, *b; int size; @@ -236,7 +240,7 @@ int xc_mem_free(xc_mem_t *mem, const void *p) /* {{{ return block size freed */ return size; } /* }}} */ -void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size) /* {{{ */ +static XC_MEM_CALLOC(xc_mem_calloc) /* {{{ */ { xc_memsize_t realsize = memb * size; void *p = xc_mem_malloc(mem, realsize); @@ -247,7 +251,7 @@ void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size) /* {{{ return p; } /* }}} */ -void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size) /* {{{ */ +static XC_MEM_REALLOC(xc_mem_realloc) /* {{{ */ { void *newp = xc_mem_malloc(mem, size); if (p) { @@ -257,7 +261,7 @@ void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size) /* {{{ */ return newp; } /* }}} */ -char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len) /* {{{ */ +static XC_MEM_STRNDUP(xc_mem_strndup) /* {{{ */ { void *p = xc_mem_malloc(mem, len + 1); if (p) { @@ -266,56 +270,54 @@ char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len) /* {{{ */ return p; } /* }}} */ -char *xc_mem_strdup(xc_mem_t *mem, const char *str) /* {{{ */ +static XC_MEM_STRDUP(xc_mem_strdup) /* {{{ */ { return xc_mem_strndup(mem, str, strlen(str)); } /* }}} */ -xc_memsize_t xc_mem_avail(xc_mem_t *mem) /* {{{ */ +static XC_MEM_AVAIL(xc_mem_avail) /* {{{ */ { return mem->avail; } /* }}} */ -xc_memsize_t xc_mem_size(xc_mem_t *mem) /* {{{ */ +static XC_MEM_SIZE(xc_mem_size) /* {{{ */ { return mem->size; } /* }}} */ -const xc_block_t *xc_mem_freeblock_first(xc_mem_t *mem) /* {{{ */ +static XC_MEM_FREEBLOCK_FIRST(xc_mem_freeblock_first) /* {{{ */ { return mem->headblock->next; } /* }}} */ -const xc_block_t *xc_mem_freeblock_next(const xc_block_t *block) /* {{{ */ +XC_MEM_FREEBLOCK_NEXT(xc_mem_freeblock_next) /* {{{ */ { return block->next; } /* }}} */ -xc_memsize_t xc_mem_block_size(const xc_block_t *block) /* {{{ */ +XC_MEM_BLOCK_SIZE(xc_mem_block_size) /* {{{ */ { return block->size; } /* }}} */ -xc_memsize_t xc_mem_block_offset(const xc_mem_t *mem, const xc_block_t *block) /* {{{ */ +XC_MEM_BLOCK_OFFSET(xc_mem_block_offset) /* {{{ */ { return ((char *) block) - ((char *) mem); } /* }}} */ -xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size) /* {{{ */ +static XC_MEM_INIT(xc_mem_init) /* {{{ */ { - xc_mem_t *mem; xc_block_t *b; - #define MINSIZE (ALIGN(sizeof(xc_mem_t)) + sizeof(xc_block_t)) /* requires at least the header and 1 tail block */ if (size < MINSIZE) { fprintf(stderr, "xc_mem_init requires %d bytes at least\n", MINSIZE); return NULL; } - mem = (xc_mem_t *) ptr; + mem->shm = shm; mem->size = size; mem->avail = size - MINSIZE; @@ -331,7 +333,7 @@ xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size) /* {{{ */ return mem; } /* }}} */ -void xc_mem_destroy(xc_mem_t *mem) /* {{{ */ +static XC_MEM_DESTROY(xc_mem_destroy) /* {{{ */ { } /* }}} */ @@ -380,3 +382,45 @@ int main() } /* }}} */ #endif + +typedef struct { + const char *name; + const xc_mem_handlers_t *handlers; +} xc_mem_scheme_t; +static xc_mem_scheme_t xc_mem_schemes[10]; + +int xc_mem_scheme_register(const char *name, const xc_mem_handlers_t *handlers) /* {{{ */ +{ + int i; + for (i = 0; i < 10; i ++) { + if (!xc_mem_schemes[i].name) { + xc_mem_schemes[i].name = name; + xc_mem_schemes[i].handlers = handlers; + return 1; + } + } + return 0; +} +/* }}} */ +const xc_mem_handlers_t *xc_mem_scheme_find(const char *name) /* {{{ */ +{ + int i; + for (i = 0; i < 10 && xc_mem_schemes[i].name; i ++) { + if (strcmp(xc_mem_schemes[i].name, name) == 0) { + return xc_mem_schemes[i].handlers; + } + } + return NULL; +} +/* }}} */ + +static xc_mem_handlers_t xc_mem_mem_handlers = XC_MEM_HANDLERS(mem); +void xc_shm_mem_init() /* {{{ */ +{ + memset(xc_mem_schemes, 0, sizeof(xc_mem_schemes)); + + if (xc_mem_scheme_register("mem", &xc_mem_mem_handlers) == 0) { + zend_error(E_ERROR, "XCache: failed to register mem mem_scheme"); + } +} +/* }}} */ diff --git a/mem.h b/mem.h index e3914cc..df630fb 100644 --- a/mem.h +++ b/mem.h @@ -2,19 +2,65 @@ typedef struct _xc_mem_t xc_mem_t; typedef struct _xc_block_t xc_block_t; typedef unsigned int xc_memsize_t; -void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size); -int xc_mem_free(xc_mem_t *mem, const void *p); -void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size); -void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size); -char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len); -char *xc_mem_strdup(xc_mem_t *mem, const char *str); -const xc_block_t *xc_mem_freeblock_first(xc_mem_t *mem); -const xc_block_t *xc_mem_freeblock_next(const xc_block_t *block); -xc_memsize_t xc_mem_block_size(const xc_block_t *block); -xc_memsize_t xc_mem_block_offset(const xc_mem_t *mem, const xc_block_t *block); +/* shm::mem */ +#define XC_MEM_MALLOC(func) void *func(xc_mem_t *mem, xc_memsize_t size) +#define XC_MEM_FREE(func) xc_memsize_t func(xc_mem_t *mem, const void *p) +#define XC_MEM_CALLOC(func) void *func(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size) +#define XC_MEM_REALLOC(func) void *func(xc_mem_t *mem, const void *p, xc_memsize_t size) +#define XC_MEM_STRNDUP(func) char *func(xc_mem_t *mem, const char *str, xc_memsize_t len) +#define XC_MEM_STRDUP(func) char *func(xc_mem_t *mem, const char *str) +#define XC_MEM_AVAIL(func) xc_memsize_t func(xc_mem_t *mem) +#define XC_MEM_SIZE(func) xc_memsize_t func(xc_mem_t *mem) +#define XC_MEM_FREEBLOCK_FIRST(func) const xc_block_t *func(xc_mem_t *mem) +#define XC_MEM_FREEBLOCK_NEXT(func) const xc_block_t *func(const xc_block_t *block) +#define XC_MEM_BLOCK_SIZE(func) xc_memsize_t func(const xc_block_t *block) +#define XC_MEM_BLOCK_OFFSET(func) xc_memsize_t func(const xc_mem_t *mem, const xc_block_t *block) -xc_memsize_t xc_mem_avail(xc_mem_t *mem); -xc_memsize_t xc_mem_size(xc_mem_t *mem); +#define XC_MEM_INIT(func) xc_mem_t *func(xc_shm_t *shm, xc_mem_t *mem, xc_memsize_t size) +#define XC_MEM_DESTROY(func) void func(xc_mem_t *mem) -xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size); -void xc_mem_destroy(xc_mem_t *mem); +#define XC_MEM_HANDLERS(name) { \ + xc_##name##_malloc \ + , xc_##name##_free \ + , xc_##name##_calloc \ + , xc_##name##_realloc \ + , xc_##name##_strndup \ + , xc_##name##_strdup \ + , xc_##name##_avail \ + , xc_##name##_size \ + , xc_##name##_freeblock_first \ + , xc_##name##_freeblock_next \ + , xc_##name##_block_size \ + , xc_##name##_block_offset \ +\ + , xc_##name##_init \ + , xc_##name##_destroy \ +} + +typedef struct { + XC_MEM_MALLOC((*malloc)); + XC_MEM_FREE((*free)); + XC_MEM_CALLOC((*calloc)); + XC_MEM_REALLOC((*realloc)); + XC_MEM_STRNDUP((*strndup)); + XC_MEM_STRDUP((*strdup)); + XC_MEM_AVAIL((*avail)); + XC_MEM_SIZE((*size)); + XC_MEM_FREEBLOCK_FIRST((*freeblock_first)); + XC_MEM_FREEBLOCK_NEXT((*freeblock_next)); + XC_MEM_BLOCK_SIZE((*block_size)); + XC_MEM_BLOCK_OFFSET((*block_offset)); + + XC_MEM_INIT((*init)); + XC_MEM_DESTROY((*destroy)); +} xc_mem_handlers_t; + +#ifndef XC_MEM_IMPL +struct _xc_mem_t { + const xc_mem_handlers_t *handlers; + xc_shm_t *shm; +}; +#endif + +int xc_mem_scheme_register(const char *name, const xc_mem_handlers_t *handlers); +const xc_mem_handlers_t *xc_mem_scheme_find(const char *name); diff --git a/mmap.c b/mmap.c index 81c37c9..ba0b28c 100644 --- a/mmap.c +++ b/mmap.c @@ -31,7 +31,8 @@ #endif #include "php.h" -#include "myshm.h" +#define XC_SHM_IMPL +#include "xc_shm.h" #ifndef max #define max(a, b) ((a) < (b) ? (b) : (a)) @@ -39,12 +40,14 @@ // {{{ xc_shm_t struct _xc_shm_t { + xc_shm_handlers_t *handlers; void *ptr; void *ptr_ro; long diff; xc_shmsize_t size; char *name; int newfile; + xc_shmsize_t memoffset; #ifdef ZEND_WIN32 HANDLE hmap; HANDLE hmap_ro; @@ -63,43 +66,43 @@ struct _xc_shm_t { #define PTR_ADD(ptr, v) (((char *) (ptr)) + (v)) #define PTR_SUB(ptr, v) (((char *) (ptr)) - (v)) -int xc_shm_can_readonly(xc_shm_t *shm) /* {{{ */ +static XC_SHM_CAN_READONLY(xc_mmap_can_readonly) /* {{{ */ { return shm->ptr_ro != NULL; } /* }}} */ -int xc_shm_is_readwrite(xc_shm_t *shm, const void *p) /* {{{ */ +static XC_SHM_IS_READWRITE(xc_mmap_is_readwrite) /* {{{ */ { return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size; } /* }}} */ -int xc_shm_is_readonly(xc_shm_t *shm, const void *p) /* {{{ */ +static XC_SHM_IS_READONLY(xc_mmap_is_readonly) /* {{{ */ { - return xc_shm_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size; + return xc_mmap_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size; } /* }}} */ -void *xc_shm_to_readwrite(xc_shm_t *shm, void *p) /* {{{ */ +static XC_SHM_TO_READWRITE(xc_mmap_to_readwrite) /* {{{ */ { if (shm->diff) { - assert(xc_shm_is_readonly(p)); + assert(xc_mmap_is_readonly(p)); p = PTR_SUB(p, shm->diff); } - assert(xc_shm_is_readwrite(p)); + assert(xc_mmap_is_readwrite(p)); return p; } /* }}} */ -void *xc_shm_to_readonly(xc_shm_t *shm, void *p) /* {{{ */ +static XC_SHM_TO_READONLY(xc_mmap_to_readonly) /* {{{ */ { assert(xc_shm_is_readwrite(p)); if (shm->diff) { p = PTR_ADD(p, shm->diff); - assert(xc_shm_is_readonly(p)); + assert(xc_mmap_is_readonly(p)); } return p; } /* }}} */ -void xc_shm_destroy(xc_shm_t *shm) /* {{{ */ +static XC_SHM_DESTROY(xc_mmap_destroy) /* {{{ */ { if (shm->ptr_ro) { munmap(shm->ptr_ro, shm->size); @@ -140,7 +143,7 @@ void xc_shm_destroy(xc_shm_t *shm) /* {{{ */ return; } /* }}} */ -xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_protection) /* {{{ */ +static XC_SHM_INIT(xc_mmap_init) /* {{{ */ { #ifdef ZEND_WIN32 # define TMP_PATH "XCache" @@ -153,6 +156,7 @@ xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_pr volatile void *romem; char tmpname[sizeof(TMP_PATH) - 1 + 100]; const char *errstr = NULL; + const char *path = (const char *) arg1; CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM"); shm->size = size; @@ -272,7 +276,7 @@ err: close(fd); } if (shm) { - xc_shm_destroy(shm); + xc_mmap_destroy(shm); } if (errstr) { fprintf(stderr, "%s\n", errstr); @@ -282,8 +286,33 @@ err: } /* }}} */ -void *xc_shm_ptr(xc_shm_t *shm) /* {{{ */ +static XC_SHM_MEMINIT(xc_mmap_meminit) /* {{{ */ +{ + xc_mem_t *mem; + if (shm->memoffset + size > shm->size) { + zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__); + return NULL; + } + mem = (xc_mem_t *) PTR_ADD(shm->ptr, shm->memoffset); + shm->memoffset += size; + mem->handlers = shm->handlers->memhandlers; + mem->handlers->init(shm, mem, size); + return mem; +} +/* }}} */ +static XC_SHM_MEMDESTROY(xc_mmap_memdestroy) /* {{{ */ +{ +} +/* }}} */ + +static xc_shm_handlers_t xc_shm_mmap_handlers = XC_SHM_HANDLERS(mmap); +void xc_shm_mmap_register() /* {{{ */ { - return shm->ptr; + CHECK(xc_shm_mmap_handlers.memhandlers = xc_mem_scheme_find("mem"), "cannot find mem handlers"); + if (xc_shm_scheme_register("mmap", &xc_shm_mmap_handlers) == 0) { + zend_error(E_ERROR, "XCache: failed to register mmap shm_scheme"); + } +err: + return; } /* }}} */ diff --git a/myshm.h b/myshm.h deleted file mode 100644 index 69c7c8d..0000000 --- a/myshm.h +++ /dev/null @@ -1,13 +0,0 @@ -typedef struct _xc_shm_t xc_shm_t; -typedef size_t xc_shmsize_t; - -int xc_shm_can_readonly(xc_shm_t *shm); -int xc_shm_is_readwrite(xc_shm_t *shm, const void *p); -int xc_shm_is_readonly(xc_shm_t *shm, const void *p); -void *xc_shm_to_readwrite(xc_shm_t *shm, void *p); -void *xc_shm_to_readonly(xc_shm_t *shm, void *p); - -void *xc_shm_ptr(xc_shm_t *shm); - -xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_protection); -void xc_shm_destroy(xc_shm_t *shm); diff --git a/processor/head.m4 b/processor/head.m4 index c8ac791..29317df 100644 --- a/processor/head.m4 +++ b/processor/head.m4 @@ -287,7 +287,7 @@ xc_entry_t *xc_processor_store_xc_entry_t(xc_entry_t *src TSRMLS_DC) { } /* mem :) */ - processor.p = (char *)xc_mem_malloc(src->cache->mem, processor.size); + processor.p = (char *) src->cache->mem->handlers->malloc(src->cache->mem, processor.size); if (processor.p == NULL) { dst = NULL; goto err_alloc; diff --git a/processor/main.m4 b/processor/main.m4 index 7f58aad..3095300 100644 --- a/processor/main.m4 +++ b/processor/main.m4 @@ -117,11 +117,11 @@ dnl }}} dnl {{{ FIXPOINTER define(`FIXPOINTER', `FIXPOINTER_EX(`$1', `dst->$2')') define(`FIXPOINTER_EX', `IFSTORE(` - $2 = ($1 *) xc_shm_to_readonly(processor->xce_src->cache->shm, (char *)$2); + $2 = ($1 *) processor->xce_src->cache->shm->handlers->to_readonly(processor->xce_src->cache->shm, (char *)$2); ')') define(`UNFIXPOINTER', `UNFIXPOINTER_EX(`$1', `dst->$2')') define(`UNFIXPOINTER_EX', `IFSTORE(` - $2 = ($1 *) xc_shm_to_readwrite(processor->xce_src->cache->shm, (char *)$2); + $2 = ($1 *) processor->xce_src->cache->shm->handlers->to_readwrite(processor->xce_src->cache->shm, (char *)$2); ')') dnl }}} dnl {{{ COPY diff --git a/utils.c b/utils.c index 29a509e..730d2a7 100644 --- a/utils.c +++ b/utils.c @@ -403,8 +403,6 @@ static void xc_sandbox_install(xc_sandbox_t *sandbox TSRMLS_DC) /* {{{ */ { int i; Bucket *b; - zend_llist_position lpos; - zend_file_handle *handle; #ifdef HAVE_XCACHE_CONSTANT b = TG(zend_constants).pListHead; diff --git a/xc_malloc.c b/xc_malloc.c new file mode 100644 index 0000000..8c165ff --- /dev/null +++ b/xc_malloc.c @@ -0,0 +1,212 @@ +#define XC_SHM_IMPL +#define XC_MEM_IMPL +#include +#include +#include +#include "xc_shm.h" +#include "php.h" +#include "align.h" + +struct _xc_mem_t { + const xc_mem_handlers_t *handlers; + xc_shm_t *shm; + xc_memsize_t size; + xc_memsize_t avail; /* total free */ +}; + +#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0) + +static XC_MEM_MALLOC(xc_malloc_malloc) /* {{{ */ +{ + return malloc(size); +} +/* }}} */ +static XC_MEM_FREE(xc_malloc_free) /* {{{ return block size freed */ +{ + free((void *) p); + return 0; +} +/* }}} */ +static XC_MEM_CALLOC(xc_malloc_calloc) /* {{{ */ +{ + return calloc(memb, size); +} +/* }}} */ +static XC_MEM_REALLOC(xc_malloc_realloc) /* {{{ */ +{ + return realloc((void *) p, size); +} +/* }}} */ +static XC_MEM_STRNDUP(xc_malloc_strndup) /* {{{ */ +{ + char *p = malloc(len); + if (!p) { + return NULL; + } + return memcpy(p, str, len); +} +/* }}} */ +static XC_MEM_STRDUP(xc_malloc_strdup) /* {{{ */ +{ + return xc_malloc_strndup(mem, str, strlen(str) + 1); +} +/* }}} */ + +static XC_MEM_AVAIL(xc_malloc_avail) /* {{{ */ +{ + return mem->avail; +} +/* }}} */ +static XC_MEM_SIZE(xc_malloc_size) /* {{{ */ +{ + return mem->size; +} +/* }}} */ + +static XC_MEM_FREEBLOCK_FIRST(xc_malloc_freeblock_first) /* {{{ */ +{ + return (void *) -1; +} +/* }}} */ +XC_MEM_FREEBLOCK_NEXT(xc_malloc_freeblock_next) /* {{{ */ +{ + return NULL; +} +/* }}} */ +XC_MEM_BLOCK_SIZE(xc_malloc_block_size) /* {{{ */ +{ + return 0; +} +/* }}} */ +XC_MEM_BLOCK_OFFSET(xc_malloc_block_offset) /* {{{ */ +{ + return 0; +} +/* }}} */ + +static XC_MEM_INIT(xc_mem_malloc_init) /* {{{ */ +{ + xc_block_t *b; + +#define MINSIZE (ALIGN(sizeof(xc_mem_t))) + /* requires at least the header and 1 tail block */ + if (size < MINSIZE) { + fprintf(stderr, "xc_mem_malloc_init requires %d bytes at least\n", MINSIZE); + return NULL; + } + mem->shm = shm; + mem->size = size; + mem->avail = size - MINSIZE; +#undef MINSIZE + + return mem; +} +/* }}} */ +static XC_MEM_DESTROY(xc_mem_malloc_destroy) /* {{{ */ +{ +} +/* }}} */ + +// {{{ xc_shm_t +struct _xc_shm_t { + xc_shm_handlers_t *handlers; + xc_shmsize_t size; + xc_shmsize_t memoffset; +}; + +#undef NDEBUG +#ifdef ALLOC_DEBUG +# define inline +#else +# define NDEBUG +#endif +#include +/* }}} */ + +static XC_SHM_CAN_READONLY(xc_malloc_can_readonly) /* {{{ */ +{ + return 0; +} +/* }}} */ +static XC_SHM_IS_READWRITE(xc_malloc_is_readwrite) /* {{{ */ +{ + return 0; +} +/* }}} */ +static XC_SHM_IS_READONLY(xc_malloc_is_readonly) /* {{{ */ +{ + return 0; +} +/* }}} */ +static XC_SHM_TO_READWRITE(xc_malloc_to_readwrite) /* {{{ */ +{ + return p; +} +/* }}} */ +static XC_SHM_TO_READONLY(xc_malloc_to_readonly) /* {{{ */ +{ + return p; +} +/* }}} */ + +static XC_SHM_DESTROY(xc_malloc_destroy) /* {{{ */ +{ + free(shm); + return; +} +/* }}} */ +static XC_SHM_INIT(xc_malloc_init) /* {{{ */ +{ + xc_shm_t *shm; + CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM"); + shm->size = size; + + return shm; +err: + return NULL; +} +/* }}} */ + +static XC_SHM_MEMINIT(xc_malloc_meminit) /* {{{ */ +{ + xc_mem_t *mem; + if (shm->memoffset + size > shm->size) { + zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__); + return NULL; + } + shm->memoffset += size; + CHECK(mem = calloc(1, sizeof(xc_mem_t)), "mem OOM"); + mem->handlers = shm->handlers->memhandlers; + mem->handlers->init(shm, mem, size); + return mem; +err: + return NULL; +} +/* }}} */ +static XC_SHM_MEMDESTROY(xc_malloc_memdestroy) /* {{{ */ +{ + mem->handlers->destroy(mem); + free(mem); +} +/* }}} */ + +#define xc_malloc_destroy xc_mem_malloc_destroy +#define xc_malloc_init xc_mem_malloc_init +static xc_mem_handlers_t xc_mem_malloc_handlers = XC_MEM_HANDLERS(malloc); +#undef xc_malloc_init +#undef xc_malloc_destroy +static xc_shm_handlers_t xc_shm_malloc_handlers = XC_SHM_HANDLERS(malloc); +void xc_shm_malloc_register() /* {{{ */ +{ + if (xc_mem_scheme_register("malloc", &xc_mem_malloc_handlers) == 0) { + zend_error(E_ERROR, "XCache: failed to register malloc mem_scheme"); + } + + CHECK(xc_shm_malloc_handlers.memhandlers = xc_mem_scheme_find("malloc"), "cannot find malloc handlers"); + if (xc_shm_scheme_register("malloc", &xc_shm_malloc_handlers) == 0) { + zend_error(E_ERROR, "XCache: failed to register malloc shm_scheme"); + } +err: + return; +} +/* }}} */ diff --git a/xc_shm.c b/xc_shm.c new file mode 100644 index 0000000..486f09a --- /dev/null +++ b/xc_shm.c @@ -0,0 +1,76 @@ +#ifdef TEST +#include +#include +#else +#include +#endif + +#include +#include +#include +#include "xc_shm.h" + +typedef struct { + const char *name; + const xc_shm_handlers_t *handlers; +} xc_shm_scheme_t; +static xc_shm_scheme_t xc_shm_schemes[10]; + +void xc_shm_init_modules() /* {{{ */ +{ + memset(xc_shm_schemes, 0, sizeof(xc_shm_schemes)); + + extern void xc_shm_mem_init(); + xc_shm_mem_init(); + + extern void xc_shm_malloc_register(); + xc_shm_malloc_register(); + + extern void xc_shm_mmap_register(); + xc_shm_mmap_register(); +} +/* }}} */ +int xc_shm_scheme_register(const char *name, const xc_shm_handlers_t *handlers) /* {{{ */ +{ + int i; + for (i = 0; i < 10; i ++) { + if (!xc_shm_schemes[i].name) { + xc_shm_schemes[i].name = name; + xc_shm_schemes[i].handlers = handlers; + return 1; + } + } + return 0; +} +/* }}} */ +const xc_shm_handlers_t *xc_shm_scheme_find(const char *name) /* {{{ */ +{ + int i; + for (i = 0; i < 10 && xc_shm_schemes[i].name; i ++) { + if (strcmp(xc_shm_schemes[i].name, name) == 0) { + return xc_shm_schemes[i].handlers; + } + } + return NULL; +} +/* }}} */ +xc_shm_t *xc_shm_init(const char *type, xc_shmsize_t size, int readonly_protection, const void *arg1, const void *arg2) /* {{{ */ +{ + const xc_shm_handlers_t *handlers = xc_shm_scheme_find(type); + + if (handlers) { + xc_shm_t *shm = handlers->init(size, readonly_protection, arg1, arg2); + if (shm) { + shm->handlers = handlers; + } + return shm; + } + + return NULL; +} +/* }}} */ +void xc_shm_destroy(xc_shm_t *shm) /* {{{ */ +{ + shm->handlers->destroy(shm); +} +/* }}} */ diff --git a/xc_shm.h b/xc_shm.h new file mode 100644 index 0000000..0b613fc --- /dev/null +++ b/xc_shm.h @@ -0,0 +1,60 @@ +typedef struct _xc_shm_t xc_shm_t; +typedef size_t xc_shmsize_t; + +#include "mem.h" + +/* shm */ +#define XC_SHM_CAN_READONLY(func) int func(xc_shm_t *shm) +#define XC_SHM_IS_READWRITE(func) int func(xc_shm_t *shm, const void *p) +#define XC_SHM_IS_READONLY(func) int func(xc_shm_t *shm, const void *p) +#define XC_SHM_TO_READWRITE(func) void *func(xc_shm_t *shm, void *p) +#define XC_SHM_TO_READONLY(func) void *func(xc_shm_t *shm, void *p) + +#define XC_SHM_INIT(func) xc_shm_t *func(xc_shmsize_t size, int readonly_protection, const void *arg1, const void *arg2) +#define XC_SHM_DESTROY(func) void func(xc_shm_t *shm) + +#define XC_SHM_MEMINIT(func) xc_mem_t *func(xc_shm_t *shm, xc_memsize_t size) +#define XC_SHM_MEMDESTROY(func) void func(xc_mem_t *mem) + +#define XC_SHM_HANDLERS(name) { \ + NULL \ + , xc_##name##_can_readonly \ + , xc_##name##_is_readwrite \ + , xc_##name##_is_readonly \ + , xc_##name##_to_readwrite \ + , xc_##name##_to_readonly \ +\ + , xc_##name##_init \ + , xc_##name##_destroy \ +\ + , xc_##name##_meminit \ + , xc_##name##_memdestroy \ +} + +typedef struct { + const xc_mem_handlers_t *memhandlers; + XC_SHM_CAN_READONLY((*can_readonly)); + XC_SHM_IS_READWRITE((*is_readwrite)); + XC_SHM_IS_READONLY((*is_readonly)); + XC_SHM_TO_READWRITE((*to_readwrite)); + XC_SHM_TO_READONLY((*to_readonly)); + XC_SHM_INIT((*init)); + XC_SHM_DESTROY((*destroy)); + + XC_SHM_MEMINIT((*meminit)); + XC_SHM_MEMDESTROY((*memdestroy)); +} xc_shm_handlers_t; + + +#ifndef XC_SHM_IMPL +struct _xc_shm_t { + const xc_shm_handlers_t *handlers; +}; +#endif + +void xc_shm_init_modules(); +int xc_shm_scheme_register(const char *name, const xc_shm_handlers_t *handlers); +const xc_shm_handlers_t *xc_shm_scheme_find(const char *name); + +xc_shm_t *xc_shm_init(const char *type, xc_shmsize_t size, int readonly_protection, const void *arg1, const void *arg2); +void xc_shm_destroy(xc_shm_t *shm); diff --git a/xcache.c b/xcache.c index 1570b37..8060540 100644 --- a/xcache.c +++ b/xcache.c @@ -67,6 +67,7 @@ /* }}} */ /* {{{ globals */ +static char *xc_shm_scheme = NULL; static char *xc_mmap_path = NULL; static char *xc_coredump_dir = NULL; @@ -150,7 +151,7 @@ static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */ /* }}} */ static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */ { - xc_mem_free(xce->cache->mem, (xc_entry_t *)xce); + xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce); } /* }}} */ static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */ @@ -252,7 +253,6 @@ typedef XC_ENTRY_APPLY_FUNC((*cache_apply_dmz_func_t)); static void xc_entry_apply_dmz(xc_cache_t *cache, cache_apply_dmz_func_t apply_func TSRMLS_DC) /* {{{ */ { xc_entry_t *p, **pp; - xc_entry_t *next; int i, c; for (i = 0, c = cache->hentry->size; i < c; i ++) { @@ -394,6 +394,7 @@ static void xc_fillinfo_dmz(int cachetype, xc_cache_t *cache, zval *return_value xc_memsize_t avail = 0; #endif xc_mem_t *mem = cache->mem; + const xc_mem_handlers_t *handlers = mem->handlers; zend_ulong interval = (cachetype == XC_TYPE_PHP) ? xc_php_gc_interval : xc_var_gc_interval; add_assoc_long_ex(return_value, ZEND_STRS("slots"), cache->hentry->size); @@ -415,25 +416,25 @@ static void xc_fillinfo_dmz(int cachetype, xc_cache_t *cache, zval *return_value MAKE_STD_ZVAL(blocks); array_init(blocks); - add_assoc_long_ex(return_value, ZEND_STRS("size"), xc_mem_size(mem)); - add_assoc_long_ex(return_value, ZEND_STRS("avail"), xc_mem_avail(mem)); + add_assoc_long_ex(return_value, ZEND_STRS("size"), handlers->size(mem)); + add_assoc_long_ex(return_value, ZEND_STRS("avail"), handlers->avail(mem)); add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection); - for (b = xc_mem_freeblock_first(mem); b; b = xc_mem_freeblock_next(b)) { + for (b = handlers->freeblock_first(mem); b; b = handlers->freeblock_next(b)) { zval *bi; MAKE_STD_ZVAL(bi); array_init(bi); - add_assoc_long_ex(bi, ZEND_STRS("size"), xc_mem_block_size(b)); - add_assoc_long_ex(bi, ZEND_STRS("offset"), xc_mem_block_offset(mem, b)); + add_assoc_long_ex(bi, ZEND_STRS("size"), handlers->block_size(b)); + add_assoc_long_ex(bi, ZEND_STRS("offset"), handlers->block_offset(mem, b)); add_next_index_zval(blocks, bi); #ifndef NDEBUG - avail += xc_mem_block_size(b); + avail += handlers->block_size(b); #endif } add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks); - assert(avail == xc_mem_avail(mem)); + assert(avail == handlers->avail(mem)); } /* }}} */ static void xc_fillentry_dmz(xc_entry_t *entry, int del, zval *list TSRMLS_DC) /* {{{ */ @@ -1024,17 +1025,20 @@ restore: /* gdb helper functions, but N/A for coredump */ int xc_is_rw(const void *p) /* {{{ */ { + xc_shm_t *shm; int i; if (!xc_initized) { return 0; } for (i = 0; i < xc_php_hcache.size; i ++) { - if (xc_shm_is_readwrite(xc_php_caches[i]->shm, p)) { + shm = xc_php_caches[i]->shm; + if (shm->handlers->is_readwrite(shm, p)) { return 1; } } for (i = 0; i < xc_var_hcache.size; i ++) { - if (xc_shm_is_readwrite(xc_var_caches[i]->shm, p)) { + shm = xc_var_caches[i]->shm; + if (shm->handlers->is_readwrite(shm, p)) { return 1; } } @@ -1043,17 +1047,20 @@ int xc_is_rw(const void *p) /* {{{ */ /* }}} */ int xc_is_ro(const void *p) /* {{{ */ { + xc_shm_t *shm; int i; if (!xc_initized) { return 0; } for (i = 0; i < xc_php_hcache.size; i ++) { - if (xc_shm_is_readonly(xc_php_caches[i]->shm, p)) { + shm = xc_php_caches[i]->shm; + if (shm->handlers->is_readonly(shm, p)) { return 1; } } for (i = 0; i < xc_var_hcache.size; i ++) { - if (xc_shm_is_readonly(xc_var_caches[i]->shm, p)) { + shm = xc_var_caches[i]->shm; + if (shm->handlers->is_readonly(shm, p)) { return 1; } } @@ -1127,11 +1134,11 @@ static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ } /* do NOT free if (cache->entries) { - xc_mem_free(cache->mem, cache->entries); + cache->mem->handlers->free(cache->mem, cache->entries); } - xc_mem_free(cache->mem, cache); + cache->mem->handlers->free(cache->mem, cache); */ - xc_mem_destroy(cache->mem); + shm->handlers->memdestroy(cache->mem); shm = cache->shm; } } @@ -1139,7 +1146,7 @@ static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ return shm; } /* }}} */ -static xc_cache_t **xc_cache_init(xc_shm_t *shm, char *ptr, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */ +static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */ { xc_cache_t **caches = NULL, *cache; xc_mem_t *mem; @@ -1163,10 +1170,9 @@ static xc_cache_t **xc_cache_init(xc_shm_t *shm, char *ptr, xc_hash_t *hcache, x CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM"); for (i = 0; i < hcache->size; i ++) { - CHECK(mem = xc_mem_init(ptr, memsize), "Failed init memory allocator"); - ptr += memsize; - CHECK(cache = xc_mem_calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM"); - CHECK(cache->entries = xc_mem_calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM"); + CHECK(mem = shm->handlers->meminit(shm, memsize), "Failed init memory allocator"); + CHECK(cache = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM"); + CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM"); CHECK(cache->lck = xc_lock_init(NULL), "can't create lock"); cache->hcache = hcache; @@ -1178,7 +1184,6 @@ static xc_cache_t **xc_cache_init(xc_shm_t *shm, char *ptr, xc_hash_t *hcache, x cache->last_gc_expires = now; caches[i] = cache; } - assert(ptr <= (char*)xc_shm_ptr(shm) + shmsize); return caches; err: @@ -1213,27 +1218,24 @@ static void xc_destroy() /* {{{ */ static int xc_init(int module_number TSRMLS_DC) /* {{{ */ { xc_shm_t *shm; - char *ptr; xc_php_caches = xc_var_caches = NULL; if (xc_php_size || xc_var_size) { - CHECK(shm = xc_shm_init(xc_mmap_path, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection), "Cannot create shm"); - if (!xc_shm_can_readonly(shm)) { + CHECK(shm = xc_shm_init(xc_shm_scheme, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection, xc_mmap_path, NULL), "Cannot create shm"); + if (!shm->handlers->can_readonly(shm)) { xc_readonly_protection = 0; } - ptr = (char *)xc_shm_ptr(shm); if (xc_php_size) { origin_compile_file = zend_compile_file; zend_compile_file = xc_compile_file; - CHECK(xc_php_caches = xc_cache_init(shm, ptr, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache"); - ptr += ALIGN(xc_php_size); + CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache"); } if (xc_var_size) { - CHECK(xc_var_caches = xc_cache_init(shm, ptr, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache"); + CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache"); } } return 1; @@ -2114,7 +2116,7 @@ PHP_INI_BEGIN() #endif PHP_INI_END() /* }}} */ -static int xc_config_long_disp(char *name, char *default_value) /* {{{ */ +static int xc_config_string_disp(char *name, char *default_value) /* {{{ */ { char *value; char buf[100]; @@ -2130,7 +2132,8 @@ static int xc_config_long_disp(char *name, char *default_value) /* {{{ */ return SUCCESS; } /* }}} */ -#define xc_config_hash_disp xc_config_long_disp +#define xc_config_hash_disp xc_config_string_disp +#define xc_config_long_disp xc_config_string_disp /* {{{ PHP_MINFO_FUNCTION(xcache) */ static PHP_MINFO_FUNCTION(xcache) { @@ -2138,7 +2141,7 @@ static PHP_MINFO_FUNCTION(xcache) char *ptr; php_info_print_table_start(); - php_info_print_table_header(2, "XCache Support", XCACHE_MODULES); + php_info_print_table_header(2, "XCache Support", "enabled"); php_info_print_table_row(2, "Version", XCACHE_VERSION); php_info_print_table_row(2, "Modules Built", XCACHE_MODULES); php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A"); @@ -2168,6 +2171,7 @@ static PHP_MINFO_FUNCTION(xcache) php_info_print_table_start(); php_info_print_table_header(2, "Directive ", "Value"); + xc_config_string_disp("xcache.shm_scheme", "mmap"); xc_config_long_disp("xcache.size", "0"); xc_config_hash_disp("xcache.count", "1"); xc_config_hash_disp("xcache.slots", "8K"); @@ -2249,6 +2253,18 @@ static int xc_config_long(zend_ulong *p, char *name, char *default_value) /* {{{ return SUCCESS; } /* }}} */ +static int xc_config_string(char **p, char *name, char *default_value) /* {{{ */ +{ + char *value; + + if (cfg_get_string(name, &value) != SUCCESS) { + value = default_value; + } + + *p = strdup(value); + return SUCCESS; +} +/* }}} */ /* {{{ PHP_MINIT_FUNCTION(xcache) */ static PHP_MINIT_FUNCTION(xcache) { @@ -2277,6 +2293,7 @@ static PHP_MINIT_FUNCTION(xcache) } } + xc_config_string(&xc_shm_scheme, "xcache.shm_scheme", "mmap"); xc_config_long(&xc_php_size, "xcache.size", "0"); xc_config_hash(&xc_php_hcache, "xcache.count", "1"); xc_config_hash(&xc_php_hentry, "xcache.slots", "8K"); @@ -2301,6 +2318,7 @@ static PHP_MINIT_FUNCTION(xcache) } xc_init_constant(module_number TSRMLS_CC); + xc_shm_init_modules(); if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) { if (!xc_init(module_number TSRMLS_CC)) { @@ -2331,6 +2349,10 @@ static PHP_MSHUTDOWN_FUNCTION(xcache) pefree(xc_mmap_path, 1); xc_mmap_path = NULL; } + if (xc_shm_scheme) { + pefree(xc_shm_scheme, 1); + xc_shm_scheme = NULL; + } #ifdef HAVE_XCACHE_COVERAGER xc_coverager_destroy(); diff --git a/xcache.h b/xcache.h index 9dc0653..a410a45 100644 --- a/xcache.h +++ b/xcache.h @@ -15,8 +15,7 @@ #ifdef HAVE_CONFIG_H #include #endif -#include "myshm.h" -#include "mem.h" +#include "xc_shm.h" #include "lock.h" #ifndef ZEND_WIN32