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;
 	}
 
