Index: /trunk/xcache.c
===================================================================
--- /trunk/xcache.c	(revision 146)
+++ /trunk/xcache.c	(revision 148)
@@ -68,4 +68,5 @@
 
 /* {{{ globals */
+static char *xc_shm_scheme = NULL;
 static char *xc_mmap_path = NULL;
 static char *xc_coredump_dir = NULL;
@@ -151,5 +152,5 @@
 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);
 }
 /* }}} */
@@ -253,5 +254,4 @@
 {
 	xc_entry_t *p, **pp;
-	xc_entry_t *next;
 	int i, c;
 
@@ -395,4 +395,5 @@
 #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;
 
@@ -416,9 +417,9 @@
 	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;
 
@@ -426,13 +427,13 @@
 		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));
 }
 /* }}} */
@@ -1025,4 +1026,5 @@
 int xc_is_rw(const void *p) /* {{{ */
 {
+	xc_shm_t *shm;
 	int i;
 	if (!xc_initized) {
@@ -1030,10 +1032,12 @@
 	}
 	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;
 		}
@@ -1044,4 +1048,5 @@
 int xc_is_ro(const void *p) /* {{{ */
 {
+	xc_shm_t *shm;
 	int i;
 	if (!xc_initized) {
@@ -1049,10 +1054,12 @@
 	}
 	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;
 		}
@@ -1128,9 +1135,9 @@
 			/* 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;
 		}
@@ -1140,5 +1147,5 @@
 }
 /* }}} */
-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;
@@ -1164,8 +1171,7 @@
 
 	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");
 
@@ -1179,5 +1185,4 @@
 		caches[i] = cache;
 	}
-	assert(ptr <= (char*)xc_shm_ptr(shm) + shmsize);
 	return caches;
 
@@ -1214,25 +1219,22 @@
 {
 	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");
 		}
 	}
@@ -2115,5 +2117,5 @@
 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;
@@ -2131,5 +2133,6 @@
 }
 /* }}} */
-#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)
@@ -2139,5 +2142,5 @@
 
 	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);
@@ -2169,4 +2172,5 @@
 	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");
@@ -2250,4 +2254,16 @@
 }
 /* }}} */
+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)
@@ -2278,4 +2294,5 @@
 	}
 
+	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");
@@ -2302,4 +2319,5 @@
 
 	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]) {
@@ -2331,4 +2349,8 @@
 		pefree(xc_mmap_path, 1);
 		xc_mmap_path = NULL;
+	}
+	if (xc_shm_scheme) {
+		pefree(xc_shm_scheme, 1);
+		xc_shm_scheme = NULL;
 	}
 
Index: /trunk/config.w32
===================================================================
--- /trunk/config.w32	(revision 95)
+++ /trunk/config.w32	(revision 148)
@@ -16,4 +16,6 @@
 	                      mmap.c \
 	                      mem.c \
+	                      xc_malloc.c \
+	                      xc_shm.c \
 	                      const_string.c \
 	                      opcode_spec.c \
Index: /trunk/xcache.h
===================================================================
--- /trunk/xcache.h	(revision 114)
+++ /trunk/xcache.h	(revision 148)
@@ -16,6 +16,5 @@
 #include <config.h>
 #endif
-#include "myshm.h"
-#include "mem.h"
+#include "xc_shm.h"
 #include "lock.h"
 
Index: /trunk/xc_malloc.c
===================================================================
--- /trunk/xc_malloc.c	(revision 148)
+++ /trunk/xc_malloc.c	(revision 148)
@@ -0,0 +1,212 @@
+#define XC_SHM_IMPL
+#define XC_MEM_IMPL
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#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 <assert.h>
+/* }}} */
+
+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;
+}
+/* }}} */
Index: /trunk/config.m4
===================================================================
--- /trunk/config.m4	(revision 95)
+++ /trunk/config.m4	(revision 148)
@@ -28,4 +28,6 @@
                   mmap.c \
                   mem.c \
+                  xc_malloc.c \
+                  xc_shm.c \
                   const_string.c \
                   opcode_spec.c \
Index: /trunk/mem.c
===================================================================
--- /trunk/mem.c	(revision 112)
+++ /trunk/mem.c	(revision 148)
@@ -9,5 +9,7 @@
 #include <stdlib.h>
 #include <string.h>
-#include "mem.h"
+#define XC_SHM_IMPL
+#define XC_MEM_IMPL
+#include "xc_shm.h"
 #include "align.h"
 
@@ -37,4 +39,6 @@
 
 struct _xc_mem_t {
+	const xc_mem_handlers_t *handlers;
+	xc_shm_t                *shm;
 	xc_memsize_t size;
 	xc_memsize_t avail;       /* total free */
@@ -75,5 +79,5 @@
 
 
-void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size) /* {{{ */
+static XC_MEM_MALLOC(xc_mem_malloc) /* {{{ */
 {
 	xc_block_t *prev, *cur;
@@ -183,5 +187,5 @@
 }
 /* }}} */
-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;
@@ -237,5 +241,5 @@
 }
 /* }}} */
-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;
@@ -248,5 +252,5 @@
 }
 /* }}} */
-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);
@@ -258,5 +262,5 @@
 }
 /* }}} */
-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);
@@ -267,5 +271,5 @@
 }
 /* }}} */
-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));
@@ -273,10 +277,10 @@
 /* }}} */
 
-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;
@@ -284,20 +288,20 @@
 /* }}} */
 
-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);
@@ -305,9 +309,7 @@
 /* }}} */
 
-xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size) /* {{{ */
-{
-	xc_mem_t   *mem;
+static XC_MEM_INIT(xc_mem_init) /* {{{ */
+{
 	xc_block_t *b;
-
 #define MINSIZE (ALIGN(sizeof(xc_mem_t)) + sizeof(xc_block_t))
 	/* requires at least the header and 1 tail block */
@@ -316,5 +318,5 @@
 		return NULL;
 	}
-	mem = (xc_mem_t *) ptr;
+	mem->shm = shm;
 	mem->size = size;
 	mem->avail = size - MINSIZE;
@@ -332,5 +334,5 @@
 }
 /* }}} */
-void xc_mem_destroy(xc_mem_t *mem) /* {{{ */
+static XC_MEM_DESTROY(xc_mem_destroy) /* {{{ */
 {
 }
@@ -381,2 +383,44 @@
 /* }}} */
 #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");
+	}
+}
+/* }}} */
Index: /trunk/xc_shm.c
===================================================================
--- /trunk/xc_shm.c	(revision 148)
+++ /trunk/xc_shm.c	(revision 148)
@@ -0,0 +1,76 @@
+#ifdef TEST
+#include <limits.h>
+#include <stdio.h>
+#else
+#include <php.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#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);
+}
+/* }}} */
Index: /trunk/mem.h
===================================================================
--- /trunk/mem.h	(revision 1)
+++ /trunk/mem.h	(revision 148)
@@ -3,18 +3,64 @@
 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);
Index: /trunk/xc_shm.h
===================================================================
--- /trunk/xc_shm.h	(revision 148)
+++ /trunk/xc_shm.h	(revision 148)
@@ -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);
Index: /trunk/mmap.c
===================================================================
--- /trunk/mmap.c	(revision 119)
+++ /trunk/mmap.c	(revision 148)
@@ -32,5 +32,6 @@
 
 #include "php.h"
-#include "myshm.h"
+#define XC_SHM_IMPL
+#include "xc_shm.h"
 
 #ifndef max
@@ -40,4 +41,5 @@
 // {{{ xc_shm_t
 struct _xc_shm_t {
+	xc_shm_handlers_t *handlers;
 	void *ptr;
 	void *ptr_ro;
@@ -46,4 +48,5 @@
 	char *name;
 	int newfile;
+	xc_shmsize_t memoffset;
 #ifdef ZEND_WIN32
 	HANDLE hmap;
@@ -64,35 +67,35 @@
 #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) /* {{{ */
-{
-	return xc_shm_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_IS_READONLY(xc_mmap_is_readonly) /* {{{ */
+{
+	return xc_mmap_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
+}
+/* }}} */
+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;
@@ -100,5 +103,5 @@
 /* }}} */
 
-void xc_shm_destroy(xc_shm_t *shm) /* {{{ */
+static XC_SHM_DESTROY(xc_mmap_destroy) /* {{{ */
 {
 	if (shm->ptr_ro) {
@@ -141,5 +144,5 @@
 }
 /* }}} */
-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
@@ -154,4 +157,5 @@
 	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");
@@ -273,5 +277,5 @@
 	}
 	if (shm) {
-		xc_shm_destroy(shm);
+		xc_mmap_destroy(shm);
 	}
 	if (errstr) {
@@ -283,7 +287,32 @@
 /* }}} */
 
-void *xc_shm_ptr(xc_shm_t *shm) /* {{{ */
-{
-	return shm->ptr;
-}
-/* }}} */
+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() /* {{{ */
+{
+	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;
+}
+/* }}} */
Index: /trunk/processor/head.m4
===================================================================
--- /trunk/processor/head.m4	(revision 103)
+++ /trunk/processor/head.m4	(revision 148)
@@ -288,5 +288,5 @@
 
 		/* 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;
Index: /trunk/processor/main.m4
===================================================================
--- /trunk/processor/main.m4	(revision 90)
+++ /trunk/processor/main.m4	(revision 148)
@@ -118,9 +118,9 @@
 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 }}}
Index: /trunk/utils.c
===================================================================
--- /trunk/utils.c	(revision 131)
+++ /trunk/utils.c	(revision 148)
@@ -404,6 +404,4 @@
 	int i;
 	Bucket *b;
-	zend_llist_position lpos;
-	zend_file_handle *handle;
 
 #ifdef HAVE_XCACHE_CONSTANT
Index: /trunk/Makefile.frag
===================================================================
--- /trunk/Makefile.frag	(revision 75)
+++ /trunk/Makefile.frag	(revision 148)
@@ -32,6 +32,6 @@
 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
Index: /unk/myshm.h
===================================================================
--- /trunk/myshm.h	(revision 11)
+++ 	(revision )
@@ -1,13 +1,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);
