static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
{
	int res;
	g_shared_alloc_handler = he->handler;
	g_shared_model = he->name;
	ZSMMG(shared_segments) = NULL;
	ZSMMG(shared_segments_count) = 0;

	res = S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in);

	if (res) {
		/* this model works! */
		return res;
	}
	if (*shared_segments_p) {
		int i;
		/* cleanup */
		for (i = 0; i < *shared_segments_count; i++) {
			if ((*shared_segments_p)[i]->p && (*shared_segments_p)[i]->p != (void *)-1) {
				S_H(detach_segment)((*shared_segments_p)[i]);
			}
		}
		free(*shared_segments_p);
		*shared_segments_p = NULL;
	}
	g_shared_alloc_handler = NULL;
	return ALLOC_FAILURE;
}
void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
{
	php_info_print_table_start();

	if (ZCG(enabled) && accel_startup_ok && (ZCG(counted) || ZCSG(accelerator_enabled))) {
		php_info_print_table_row(2, "Opcode Caching", "Up and Running");
	} else {
		php_info_print_table_row(2, "Opcode Caching", "Disabled");
	}
	if (ZCG(enabled) && accel_startup_ok && ZCSG(accelerator_enabled) && ZCG(accel_directives).optimization_level) {
		php_info_print_table_row(2, "Optimization", "Enabled");
	} else {
		php_info_print_table_row(2, "Optimization", "Disabled");
	}
	if (ZCG(enabled)) {
		if (!accel_startup_ok || zps_api_failure_reason) {
			php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
		} else {
			char buf[32];
			php_info_print_table_row(2, "Startup", "OK");
			php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model());
			snprintf(buf, sizeof(buf), "%ld", ZCSG(hits));
			php_info_print_table_row(2, "Cache hits", buf);
			snprintf(buf, sizeof(buf), "%ld", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
			php_info_print_table_row(2, "Cache misses", buf);
			snprintf(buf, sizeof(buf), "%ld", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
			php_info_print_table_row(2, "Used memory", buf);
			snprintf(buf, sizeof(buf), "%ld", zend_shared_alloc_get_free_memory());
			php_info_print_table_row(2, "Free memory", buf);
			snprintf(buf, sizeof(buf), "%ld", ZSMMG(wasted_shared_memory));
			php_info_print_table_row(2, "Wasted memory", buf);
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
			if (ZCSG(interned_strings_start) && ZCSG(interned_strings_end) && ZCSG(interned_strings_top)) {
				snprintf(buf, sizeof(buf), "%ld", ZCSG(interned_strings_top) - ZCSG(interned_strings_start));
				php_info_print_table_row(2, "Interned Strings Used memory", buf);
				snprintf(buf, sizeof(buf), "%ld", ZCSG(interned_strings_end) - ZCSG(interned_strings_top));
				php_info_print_table_row(2, "Interned Strings Free memory", buf);
			}
#endif
			snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).num_direct_entries);
			php_info_print_table_row(2, "Cached scripts", buf);
			snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).num_entries);
			php_info_print_table_row(2, "Cached keys", buf);
			snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).max_num_entries);
			php_info_print_table_row(2, "Max keys", buf);
			snprintf(buf, sizeof(buf), "%ld", ZCSG(oom_restarts));
			php_info_print_table_row(2, "OOM restarts", buf);
			snprintf(buf, sizeof(buf), "%ld", ZCSG(hash_restarts));
			php_info_print_table_row(2, "Hash keys restarts", buf);
			snprintf(buf, sizeof(buf), "%ld", ZCSG(manual_restarts));
			php_info_print_table_row(2, "Manual restarts", buf);
		}
	}

	php_info_print_table_end();
	DISPLAY_INI_ENTRIES();
}
void *zend_shared_alloc(size_t size)
{
	int i;
	unsigned int block_size = ZEND_ALIGNED_SIZE(size);

#if 1
	if (!ZCG(locked)) {
		zend_accel_error(ACCEL_LOG_ERROR, "Shared memory lock not obtained");
	}
#endif
	if (block_size > ZSMMG(shared_free)) { /* No hope to find a big-enough block */
		SHARED_ALLOC_FAILED();
		return NULL;
	}
	for (i = 0; i < ZSMMG(shared_segments_count); i++) {
		if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
			void *retval = (void *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);

			ZSMMG(shared_segments)[i]->pos += block_size;
			ZSMMG(shared_free) -= block_size;
			memset(retval, 0, block_size);
			ZEND_ASSERT(((zend_uintptr_t)retval & 0x7) == 0); /* should be 8 byte aligned */
			return retval;
		}
	}
	SHARED_ALLOC_FAILED();
	return NULL;
}
static size_t zend_shared_alloc_get_largest_free_block(void)
{
	int i;
	size_t largest_block_size = 0;

	for (i = 0; i < ZSMMG(shared_segments_count); i++) {
		size_t block_size = ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos;

		if (block_size>largest_block_size) {
			largest_block_size = block_size;
		}
	}
	return largest_block_size;
}
/* {{{ proto array accelerator_get_status()
   Obtain statistics information regarding code acceleration in the Zend Performance Suite */
static ZEND_FUNCTION(accelerator_get_status)
{
	long reqs;
	zval *memory_usage,*statistics,*scripts;

	/* keep the compiler happy */
	(void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;

	if (!ZCG(startup_ok) || !ZCSG(accelerator_enabled)) {
		RETURN_FALSE;
	}

	array_init(return_value);

	/* Trivia */
	add_assoc_bool(return_value, "accelerator_enabled", 1 /*ZCG(startup_ok) && ZCSG(accelerator_enabled)*/);
	add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));

	/* Memory usage statistics */
	MAKE_STD_ZVAL(memory_usage);
	array_init(memory_usage);
	add_assoc_long(memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
	add_assoc_long(memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
	add_assoc_long(memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
	add_assoc_double(memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
	add_assoc_zval(return_value, "memory_usage",memory_usage);

	/* Accelerator statistics */
	MAKE_STD_ZVAL(statistics);
	array_init(statistics);
	add_assoc_long(statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
	add_assoc_long(statistics, "max_cached_scripts", ZCSG(hash).max_num_entries);
	add_assoc_long(statistics, "hits", ZCSG(hits));
	add_assoc_long(statistics, "last_restart_time", ZCSG(last_restart_time));
	add_assoc_long(statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
	add_assoc_long(statistics, "blacklist_misses", ZCSG(blacklist_misses));
	reqs = ZCSG(hits)+ZCSG(misses);
	add_assoc_double(statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
	add_assoc_double(statistics, "accelerator_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
	add_assoc_zval(return_value, "accelerator_statistics",statistics);

	/* acceleratred scripts */
	scripts=accelerator_get_scripts(TSRMLS_C);
	if( scripts ){
		add_assoc_zval(return_value, "scripts",scripts);
	}
}
void zend_shared_alloc_shutdown(void)
{
	zend_shared_segment **tmp_shared_segments;
	size_t shared_segments_array_size;
	zend_smm_shared_globals tmp_shared_globals;
	int i;

	tmp_shared_globals = *smm_shared_globals;
	smm_shared_globals = &tmp_shared_globals;
	shared_segments_array_size = ZSMMG(shared_segments_count) * (S_H(segment_type_size)() + sizeof(void *));
	tmp_shared_segments = emalloc(shared_segments_array_size);
	copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
	ZSMMG(shared_segments) = tmp_shared_segments;

	for (i = 0; i < ZSMMG(shared_segments_count); i++) {
		S_H(detach_segment)(ZSMMG(shared_segments)[i]);
	}
	efree(ZSMMG(shared_segments));
	ZSMMG(shared_segments) = NULL;
	g_shared_alloc_handler = NULL;
#ifndef ZEND_WIN32
	close(lock_file);
#endif
}
void *zend_shared_alloc(size_t size)
{
	int i;
	unsigned int block_size = size + sizeof(zend_shared_memory_block_header);
	TSRMLS_FETCH();

#if 1
	if (!ZCG(locked)) {
		zend_accel_error(ACCEL_LOG_ERROR, "Shared memory lock not obtained");
	}
#endif
	if (block_size > ZSMMG(shared_free)) { /* No hope to find a big-enough block */
		SHARED_ALLOC_FAILED();
		return NULL;
	}
	for (i = 0; i < ZSMMG(shared_segments_count); i++) {
		if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
			zend_shared_memory_block_header *p = (zend_shared_memory_block_header *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);
			int remainder = block_size % PLATFORM_ALIGNMENT;
			void *retval;

			if (remainder != 0) {
				size += PLATFORM_ALIGNMENT - remainder;
				block_size += PLATFORM_ALIGNMENT - remainder;
			}
			ZSMMG(shared_segments)[i]->pos += block_size;
			ZSMMG(shared_free) -= block_size;
			p->size = size;
			retval = ((char *) p) + sizeof(zend_shared_memory_block_header);
			memset(retval, 0, size);
			return retval;
		}
	}
	SHARED_ALLOC_FAILED();
	return NULL;
}
/* {{{ proto array accelerator_get_status([bool fetch_scripts])
   Obtain statistics information regarding code acceleration */
static ZEND_FUNCTION(opcache_get_status)
{
	long reqs;
	zval *memory_usage,*statistics,*scripts;
	zend_bool fetch_scripts = 1;

	/* keep the compiler happy */
	(void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &fetch_scripts) == FAILURE) {
		return;
	}
	
	if (!accel_startup_ok) {
		RETURN_FALSE;
	}

	array_init(return_value);

	/* Trivia */
	add_assoc_bool(return_value, "opcache_enabled", ZCG(enabled) && (ZCG(counted) || ZCSG(accelerator_enabled)));
	add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
	add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
	add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));

	/* Memory usage statistics */
	MAKE_STD_ZVAL(memory_usage);
	array_init(memory_usage);
	add_assoc_long(memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
	add_assoc_long(memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
	add_assoc_long(memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
	add_assoc_double(memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
	add_assoc_zval(return_value, "memory_usage", memory_usage);

	/* Accelerator statistics */
	MAKE_STD_ZVAL(statistics);
	array_init(statistics);
	add_assoc_long(statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
	add_assoc_long(statistics, "num_cached_keys",    ZCSG(hash).num_entries);
	add_assoc_long(statistics, "max_cached_keys",    ZCSG(hash).max_num_entries);
	add_assoc_long(statistics, "hits", ZCSG(hits));
	add_assoc_long(statistics, "start_time", ZCSG(start_time));
	add_assoc_long(statistics, "last_restart_time", ZCSG(last_restart_time));
	add_assoc_long(statistics, "oom_restarts", ZCSG(oom_restarts));
	add_assoc_long(statistics, "hash_restarts", ZCSG(hash_restarts));
	add_assoc_long(statistics, "manual_restarts", ZCSG(manual_restarts));
	add_assoc_long(statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
	add_assoc_long(statistics, "blacklist_misses", ZCSG(blacklist_misses));
	reqs = ZCSG(hits)+ZCSG(misses);
	add_assoc_double(statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
	add_assoc_double(statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
	add_assoc_zval(return_value, "opcache_statistics", statistics);

	if (fetch_scripts) {
		/* accelerated scripts */
		scripts = accelerator_get_scripts(TSRMLS_C);
		if (scripts) {
			add_assoc_zval(return_value, "scripts", scripts);
		}
	}
}
Exemple #9
0
zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle)
{
	zend_string *full_path = file_handle->opened_path;
	int fd;
	char *filename;
	zend_persistent_script *script;
	zend_file_cache_metainfo info;
	zend_accel_hash_entry *bucket;
	void *mem, *checkpoint, *buf;
	int cache_it = 1;

	if (!full_path) {
		return NULL;
	}
	filename = zend_file_cache_get_bin_file_path(full_path);

	fd = open(filename, O_RDONLY | O_BINARY);
	if (fd < 0) {
		efree(filename);
		return NULL;
	}

	if (zend_file_cache_flock(fd, LOCK_SH) != 0) {
		close(fd);
		efree(filename);
		return NULL;
	}

	if (read(fd, &info, sizeof(info)) != sizeof(info)) {
		zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename);
		zend_file_cache_flock(fd, LOCK_UN);
		close(fd);
		unlink(filename);
		efree(filename);
		return NULL;
	}

	/* verify header */
	if (memcmp(info.magic, "OPCACHE", 8) != 0) {
		zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong header)\n", filename);
		zend_file_cache_flock(fd, LOCK_UN);
		close(fd);
		unlink(filename);
		efree(filename);
		return NULL;
	}
	if (memcmp(info.system_id, ZCG(system_id), 32) != 0) {
		zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong \"system_id\")\n", filename);
		zend_file_cache_flock(fd, LOCK_UN);
		close(fd);
		unlink(filename);
		efree(filename);
		return NULL;
	}

	/* verify timestamp */
	if (ZCG(accel_directives).validate_timestamps &&
	    zend_get_file_handle_timestamp(file_handle, NULL) != info.timestamp) {
		if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
			zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
		}
		close(fd);
		unlink(filename);
		efree(filename);
		return NULL;
	}

	checkpoint = zend_arena_checkpoint(CG(arena));
#ifdef __SSE2__
	/* Align to 64-byte boundary */
	mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size + 64);
	mem = (void*)(((zend_uintptr_t)mem + 63L) & ~63L);
#else
	mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size);
#endif

	if (read(fd, mem, info.mem_size + info.str_size) != (ssize_t)(info.mem_size + info.str_size)) {
		zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename);
		zend_file_cache_flock(fd, LOCK_UN);
		close(fd);
		unlink(filename);
		zend_arena_release(&CG(arena), checkpoint);
		efree(filename);
		return NULL;
	}
	if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
		zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
	}
	close(fd);

	/* verify checksum */
	if (ZCG(accel_directives).file_cache_consistency_checks &&
	    zend_adler32(ADLER32_INIT, mem, info.mem_size + info.str_size) != info.checksum) {
		zend_accel_error(ACCEL_LOG_WARNING, "corrupted file '%s'\n", filename);
		unlink(filename);
		zend_arena_release(&CG(arena), checkpoint);
		efree(filename);
		return NULL;
	}

	if (!ZCG(accel_directives).file_cache_only &&
	    !ZCSG(restart_in_progress) &&
	    accelerator_shm_read_lock() == SUCCESS) {
		/* exclusive lock */
		zend_shared_alloc_lock();

		/* Check if we still need to put the file into the cache (may be it was
		 * already stored by another process. This final check is done under
		 * exclusive lock) */
		bucket = zend_accel_hash_find_entry(&ZCSG(hash), full_path);
		if (bucket) {
			script = (zend_persistent_script *)bucket->data;
			if (!script->corrupted) {
				zend_shared_alloc_unlock();
				zend_arena_release(&CG(arena), checkpoint);
				efree(filename);
				return script;
			}
		}

		if (zend_accel_hash_is_full(&ZCSG(hash))) {
			zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
			ZSMMG(memory_exhausted) = 1;
			zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
			zend_shared_alloc_unlock();
			goto use_process_mem;
		}

#ifdef __SSE2__
		/* Align to 64-byte boundary */
		buf = zend_shared_alloc(info.mem_size + 64);
		buf = (void*)(((zend_uintptr_t)buf + 63L) & ~63L);
#else
		buf = zend_shared_alloc(info.mem_size);
#endif

		if (!buf) {
			zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
			zend_shared_alloc_unlock();
			goto use_process_mem;
		}
		memcpy(buf, mem, info.mem_size);
	} else {
use_process_mem:
		buf = mem;
		cache_it = 0;
	}

	ZCG(mem) = ((char*)mem + info.mem_size);
	script = (zend_persistent_script*)((char*)buf + info.script_offset);
	script->corrupted = !cache_it; /* used to check if script restored to SHM or process memory */
	zend_file_cache_unserialize(script, buf);
	script->corrupted = 0;

	if (cache_it) {
		script->dynamic_members.checksum = zend_accel_script_checksum(script);
		script->dynamic_members.last_used = ZCG(request_time);

		zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(script->script.filename), ZSTR_LEN(script->script.filename), 0, script);

		zend_shared_alloc_unlock();
		zend_arena_release(&CG(arena), checkpoint);
	}
	efree(filename);

	return script;
}
/* {{{ proto array accelerator_get_status([bool fetch_scripts])
   Obtain statistics information regarding code acceleration */
static ZEND_FUNCTION(opcache_get_status)
{
	zend_long reqs;
	zval memory_usage, statistics, scripts;
	zend_bool fetch_scripts = 1;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &fetch_scripts) == FAILURE) {
		return;
	}

	if (!validate_api_restriction()) {
		RETURN_FALSE;
	}

	if (!accel_startup_ok) {
		RETURN_FALSE;
	}

	array_init(return_value);

	/* Trivia */
	add_assoc_bool(return_value, "opcache_enabled", ZCG(enabled) && (ZCG(counted) || ZCSG(accelerator_enabled)));

#ifdef HAVE_OPCACHE_FILE_CACHE
	if (ZCG(accel_directives).file_cache) {
		add_assoc_string(return_value, "file_cache", ZCG(accel_directives).file_cache);
	}
	if (ZCG(accel_directives).file_cache_only) {
		add_assoc_bool(return_value, "file_cache_only", 1);
		return;
	}
#endif

	add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
	add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
	add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));

	/* Memory usage statistics */
	array_init(&memory_usage);
	add_assoc_long(&memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
	add_assoc_long(&memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
	add_assoc_long(&memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
	add_assoc_double(&memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
	add_assoc_zval(return_value, "memory_usage", &memory_usage);

	if (ZCSG(interned_strings_start) && ZCSG(interned_strings_end) && ZCSG(interned_strings_top)) {
		zval interned_strings_usage;

		array_init(&interned_strings_usage);
		add_assoc_long(&interned_strings_usage, "buffer_size", ZCSG(interned_strings_end) - ZCSG(interned_strings_start));
		add_assoc_long(&interned_strings_usage, "used_memory", ZCSG(interned_strings_top) - ZCSG(interned_strings_start));
		add_assoc_long(&interned_strings_usage, "free_memory", ZCSG(interned_strings_end) - ZCSG(interned_strings_top));
		add_assoc_long(&interned_strings_usage, "number_of_strings", ZCSG(interned_strings).nNumOfElements);
		add_assoc_zval(return_value, "interned_strings_usage", &interned_strings_usage);
	}

	/* Accelerator statistics */
	array_init(&statistics);
	add_assoc_long(&statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
	add_assoc_long(&statistics, "num_cached_keys",    ZCSG(hash).num_entries);
	add_assoc_long(&statistics, "max_cached_keys",    ZCSG(hash).max_num_entries);
	add_assoc_long(&statistics, "hits", (zend_long)ZCSG(hits));
	add_assoc_long(&statistics, "start_time", ZCSG(start_time));
	add_assoc_long(&statistics, "last_restart_time", ZCSG(last_restart_time));
	add_assoc_long(&statistics, "oom_restarts", ZCSG(oom_restarts));
	add_assoc_long(&statistics, "hash_restarts", ZCSG(hash_restarts));
	add_assoc_long(&statistics, "manual_restarts", ZCSG(manual_restarts));
	add_assoc_long(&statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
	add_assoc_long(&statistics, "blacklist_misses", ZCSG(blacklist_misses));
	reqs = ZCSG(hits)+ZCSG(misses);
	add_assoc_double(&statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
	add_assoc_double(&statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
	add_assoc_zval(return_value, "opcache_statistics", &statistics);

	if (fetch_scripts) {
		/* accelerated scripts */
		if (accelerator_get_scripts(&scripts)) {
			add_assoc_zval(return_value, "scripts", &scripts);
		}
	}
}
int zend_shared_alloc_startup(size_t requested_size)
{
	zend_shared_segment **tmp_shared_segments;
	size_t shared_segments_array_size;
	zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals;
	char *error_in = NULL;
	const zend_shared_memory_handler_entry *he;
	int res = ALLOC_FAILURE;


	/* shared_free must be valid before we call zend_shared_alloc()
	 * - make it temporarily point to a local variable
	 */
	smm_shared_globals = &tmp_shared_globals;
	ZSMMG(shared_free) = requested_size; /* goes to tmp_shared_globals.shared_free */

	zend_shared_alloc_create_lock();

	if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) {
		char *model = ZCG(accel_directives).memory_model;
		/* "cgi" is really "shm"... */
		if (strncmp(ZCG(accel_directives).memory_model, "cgi", sizeof("cgi")) == 0) {
			model = "shm";
		}

		for (he = handler_table; he->name; he++) {
			if (strcmp(model, he->name) == 0) {
				res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
				if (res) {
					/* this model works! */
				}
				break;
			}
		}
	}

	if (res == FAILED_REATTACHED) {
		smm_shared_globals = NULL;
		return res;
	}
#if ENABLE_FILE_CACHE_FALLBACK
	if (ALLOC_FALLBACK == res) {
		return ALLOC_FALLBACK;
	}
#endif

	if (!g_shared_alloc_handler) {
		/* try memory handlers in order */
		for (he = handler_table; he->name; he++) {
			res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
			if (res) {
				/* this model works! */
				break;
			}
		}
	}

	if (!g_shared_alloc_handler) {
		no_memory_bailout(requested_size, error_in);
		return ALLOC_FAILURE;
	}

	if (res == SUCCESSFULLY_REATTACHED) {
		return res;
	}
#if ENABLE_FILE_CACHE_FALLBACK
	if (ALLOC_FALLBACK == res) {
		return ALLOC_FALLBACK;
	}
#endif

	shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)();

	/* move shared_segments and shared_free to shared memory */
	ZCG(locked) = 1; /* no need to perform a real lock at this point */
	p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals));
	if (!p_tmp_shared_globals) {
		zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
		return ALLOC_FAILURE;;
	}

	tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *));
	if (!tmp_shared_segments) {
		zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
		return ALLOC_FAILURE;;
	}

	copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());

	*p_tmp_shared_globals = tmp_shared_globals;
	smm_shared_globals = p_tmp_shared_globals;

	free(ZSMMG(shared_segments));
	ZSMMG(shared_segments) = tmp_shared_segments;

	ZSMMG(shared_memory_state).positions = (int *)zend_shared_alloc(sizeof(int) * ZSMMG(shared_segments_count));
	if (!ZSMMG(shared_memory_state).positions) {
		zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
		return ALLOC_FAILURE;;
	}

	ZCG(locked) = 0;

	return res;
}