X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?p=php5-apc.git;a=blobdiff_plain;f=php_apc.c;fp=php_apc.c;h=f7b7a7b32db06a21fff6413e41eef6dec477aeb3;hp=0000000000000000000000000000000000000000;hb=27531cfcd6e8fb46402c6771ef4c2d97233917af;hpb=5ee5738a895adae39c3e6ad85f158331cc89d522 diff --git a/php_apc.c b/php_apc.c new file mode 100644 index 0000000..f7b7a7b --- /dev/null +++ b/php_apc.c @@ -0,0 +1,991 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | + | Rasmus Lerdorf | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. + Future revisions and derivatives of this source code must acknowledge + Community Connect Inc. as the original contributor of this module by + leaving this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: php_apc.c,v 3.154 2007/12/26 22:31:20 rasmus Exp $ */ + +#include "apc_zend.h" +#include "apc_cache.h" +#include "apc_main.h" +#include "apc_sma.h" +#include "apc_lock.h" +#include "php_globals.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "SAPI.h" +#include "rfc1867.h" +#include "php_apc.h" +#if PHP_API_VERSION <= 20020918 +#if HAVE_APACHE +#ifdef APC_PHP4_STAT +#undef XtOffsetOf +#include "httpd.h" +#endif +#endif +#endif + +#if HAVE_SIGACTION +#include "apc_signal.h" +#endif + +/* {{{ PHP_FUNCTION declarations */ +PHP_FUNCTION(apc_cache_info); +PHP_FUNCTION(apc_clear_cache); +PHP_FUNCTION(apc_sma_info); +PHP_FUNCTION(apc_store); +PHP_FUNCTION(apc_fetch); +PHP_FUNCTION(apc_delete); +PHP_FUNCTION(apc_compile_file); +PHP_FUNCTION(apc_define_constants); +PHP_FUNCTION(apc_load_constants); +PHP_FUNCTION(apc_add); +/* }}} */ + +/* {{{ ZEND_DECLARE_MODULE_GLOBALS(apc) */ +ZEND_DECLARE_MODULE_GLOBALS(apc) + +/* True globals */ +apc_cache_t* apc_cache = NULL; +apc_cache_t* apc_user_cache = NULL; +void* apc_compiled_filters = NULL; + +static void php_apc_init_globals(zend_apc_globals* apc_globals TSRMLS_DC) +{ + apc_globals->filters = NULL; + apc_globals->initialized = 0; + apc_globals->cache_stack = apc_stack_create(0); + apc_globals->cache_by_default = 1; + apc_globals->slam_defense = 0; + apc_globals->mem_size_ptr = NULL; + apc_globals->fpstat = 1; + apc_globals->stat_ctime = 0; + apc_globals->write_lock = 1; + apc_globals->report_autofilter = 0; + apc_globals->apc_optimize_function = NULL; +#ifdef MULTIPART_EVENT_FORMDATA + apc_globals->rfc1867 = 0; +#endif + apc_globals->copied_zvals = NULL; +#ifdef ZEND_ENGINE_2 + apc_globals->reserved_offset = -1; +#endif + apc_globals->localcache = 0; + apc_globals->localcache_size = 0; + apc_globals->lcache = NULL; + apc_globals->force_file_update = 0; + apc_globals->coredump_unmap = 0; +} + +static void php_apc_shutdown_globals(zend_apc_globals* apc_globals TSRMLS_DC) +{ + /* deallocate the ignore patterns */ + if (apc_globals->filters != NULL) { + int i; + for (i=0; apc_globals->filters[i] != NULL; i++) { + apc_efree(apc_globals->filters[i]); + } + apc_efree(apc_globals->filters); + } + + /* the stack should be empty */ + assert(apc_stack_size(apc_globals->cache_stack) == 0); + + /* apc cleanup */ + apc_stack_destroy(apc_globals->cache_stack); + + /* the rest of the globals are cleaned up in apc_module_shutdown() */ +} + +/* }}} */ + +/* {{{ PHP_INI */ + +static PHP_INI_MH(OnUpdate_filters) /* {{{ */ +{ + APCG(filters) = apc_tokenize(new_value, ','); + return SUCCESS; +} +/* }}} */ + +static PHP_INI_MH(OnUpdateShmSegments) /* {{{ */ +{ +#if APC_MMAP + if(atoi(new_value)!=1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "apc.shm_segments setting ignored in MMAP mode"); + } + APCG(shm_segments) = 1; +#else + APCG(shm_segments) = atoi(new_value); +#endif + return SUCCESS; +} +/* }}} */ + +#ifdef MULTIPART_EVENT_FORMDATA +static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */ +{ + int tmp; + tmp = zend_atoi(new_value, new_value_length); + if(tmp < 0) { + apc_eprint("rfc1867_freq must be greater than or equal to zero."); + return FAILURE; + } + if(new_value[new_value_length-1] == '%') { + if(tmp > 100) { + apc_eprint("rfc1867_freq cannot be over 100%%"); + return FAILURE; + } + APCG(rfc1867_freq) = tmp / 100.0; + } else { + APCG(rfc1867_freq) = tmp; + } + return SUCCESS; +} +/* }}} */ +#endif + +#ifdef ZEND_ENGINE_2 +#define OnUpdateInt OnUpdateLong +#endif + +PHP_INI_BEGIN() +STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.shm_size", "30", PHP_INI_SYSTEM, OnUpdateInt, shm_size, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.include_once_override", "0", PHP_INI_SYSTEM, OnUpdateBool, include_once, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.num_files_hint", "1000", PHP_INI_SYSTEM, OnUpdateInt, num_files_hint, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.user_entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateInt, user_entries_hint, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateInt, gc_ttl, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, ttl, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.user_ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, user_ttl, zend_apc_globals, apc_globals) +#if APC_MMAP +STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apc_globals, apc_globals) +#endif +PHP_INI_ENTRY("apc.filters", NULL, PHP_INI_SYSTEM, OnUpdate_filters) +STD_PHP_INI_BOOLEAN("apc.cache_by_default", "1", PHP_INI_ALL, OnUpdateBool, cache_by_default, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.slam_defense", "0", PHP_INI_SYSTEM, OnUpdateInt, slam_defense, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.file_update_protection", "2", PHP_INI_SYSTEM, OnUpdateInt,file_update_protection, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.max_file_size", "1M", PHP_INI_SYSTEM, OnUpdateInt, max_file_size, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.stat", "1", PHP_INI_SYSTEM, OnUpdateBool, fpstat, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.stat_ctime", "0", PHP_INI_SYSTEM, OnUpdateBool, stat_ctime, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.write_lock", "1", PHP_INI_SYSTEM, OnUpdateBool, write_lock, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.report_autofilter", "0", PHP_INI_SYSTEM, OnUpdateBool, report_autofilter,zend_apc_globals, apc_globals) +#ifdef MULTIPART_EVENT_FORMDATA +STD_PHP_INI_BOOLEAN("apc.rfc1867", "0", PHP_INI_SYSTEM, OnUpdateBool, rfc1867, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.rfc1867_prefix", "upload_", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_prefix, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.rfc1867_name", "APC_UPLOAD_PROGRESS", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_name, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.rfc1867_freq", "0", PHP_INI_SYSTEM, OnUpdateRfc1867Freq, rfc1867_freq, zend_apc_globals, apc_globals) +#endif +STD_PHP_INI_BOOLEAN("apc.localcache", "0", PHP_INI_SYSTEM, OnUpdateBool, localcache, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.localcache.size", "512", PHP_INI_SYSTEM, OnUpdateInt, localcache_size, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.coredump_unmap", "0", PHP_INI_SYSTEM, OnUpdateBool, coredump_unmap, zend_apc_globals, apc_globals) +PHP_INI_END() + +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION(apc) */ +static PHP_MINFO_FUNCTION(apc) +{ + php_info_print_table_start(); + php_info_print_table_row(2, "APC Support", APCG(enabled) ? "enabled" : "disabled"); + php_info_print_table_row(2, "Version", APC_VERSION); +#if APC_MMAP + php_info_print_table_row(2, "MMAP Support", "Enabled"); + php_info_print_table_row(2, "MMAP File Mask", APCG(mmap_file_mask)); +#else + php_info_print_table_row(2, "MMAP Support", "Disabled"); +#endif +#if APC_SEM_LOCKS + php_info_print_table_row(2, "Locking type", "IPC Semaphore"); +#elif APC_FUTEX_LOCKS + php_info_print_table_row(2, "Locking type", "Linux Futex Locks"); +#elif APC_PTHREADMUTEX_LOCKS + php_info_print_table_row(2, "Locking type", "pthread mutex Locks"); +#elif APC_SPIN_LOCKS + php_info_print_table_row(2, "Locking type", "spin Locks"); +#else + php_info_print_table_row(2, "Locking type", "File Locks"); +#endif + php_info_print_table_row(2, "Revision", "$Revision: 3.154 $"); + php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__); + php_info_print_table_end(); + DISPLAY_INI_ENTRIES(); +} +/* }}} */ + +#ifdef MULTIPART_EVENT_FORMDATA +extern int apc_rfc1867_progress(unsigned int event, void *event_data, void **extra TSRMLS_DC); +#endif + +/* {{{ PHP_MINIT_FUNCTION(apc) */ +static PHP_MINIT_FUNCTION(apc) +{ + ZEND_INIT_MODULE_GLOBALS(apc, php_apc_init_globals, php_apc_shutdown_globals); + + REGISTER_INI_ENTRIES(); + + /* Disable APC in cli mode unless overridden by apc.enable_cli */ + if(!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) { + APCG(enabled) = 0; + } + + if (APCG(enabled)) { + if(APCG(initialized)) { + apc_process_init(module_number TSRMLS_CC); + } else { + apc_module_init(module_number TSRMLS_CC); + apc_zend_init(TSRMLS_C); + apc_process_init(module_number TSRMLS_CC); +#ifdef MULTIPART_EVENT_FORMDATA + /* File upload progress tracking */ + if(APCG(rfc1867)) { + php_rfc1867_callback = apc_rfc1867_progress; + } +#endif + } + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION(apc) */ +static PHP_MSHUTDOWN_FUNCTION(apc) +{ + if(APCG(enabled)) { + apc_process_shutdown(TSRMLS_C); + apc_zend_shutdown(TSRMLS_C); + apc_module_shutdown(TSRMLS_C); +#ifndef ZTS + php_apc_shutdown_globals(&apc_globals); +#endif + } +#ifdef ZTS + ts_free_id(apc_globals_id); +#endif + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RINIT_FUNCTION(apc) */ +static PHP_RINIT_FUNCTION(apc) +{ + if(APCG(enabled)) { + apc_request_init(TSRMLS_C); + +#if HAVE_SIGACTION + apc_set_signals(); +#endif + } + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RSHUTDOWN_FUNCTION(apc) */ +static PHP_RSHUTDOWN_FUNCTION(apc) +{ + if(APCG(enabled)) { + apc_request_shutdown(TSRMLS_C); + } + return SUCCESS; +} +/* }}} */ + +/* {{{ proto array apc_cache_info([string type] [, bool limited]) */ +PHP_FUNCTION(apc_cache_info) +{ + apc_cache_info_t* info; + apc_cache_link_t* p; + zval* list; + char *cache_type; + int ct_len; + zend_bool limited=0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &cache_type, &ct_len, &limited) == FAILURE) { + return; + } + + if(ZEND_NUM_ARGS()) { + if(!strcasecmp(cache_type,"user")) { + info = apc_cache_info(apc_user_cache, limited); + } else if(!strcasecmp(cache_type,"filehits")) { +#ifdef APC_FILEHITS + RETVAL_ZVAL(APCG(filehits), 1, 0); + return; +#else + RETURN_FALSE; +#endif + } else { + info = apc_cache_info(apc_cache, limited); + } + } else info = apc_cache_info(apc_cache, limited); + + if(!info) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file"); + RETURN_FALSE; + } + + array_init(return_value); + add_assoc_long(return_value, "num_slots", info->num_slots); + add_assoc_long(return_value, "ttl", info->ttl); + add_assoc_long(return_value, "num_hits", info->num_hits); + add_assoc_long(return_value, "num_misses", info->num_misses); + add_assoc_long(return_value, "start_time", info->start_time); + add_assoc_long(return_value, "expunges", info->expunges); + add_assoc_long(return_value, "mem_size", info->mem_size); + add_assoc_long(return_value, "num_entries", info->num_entries); + add_assoc_long(return_value, "num_inserts", info->num_inserts); +#ifdef MULTIPART_EVENT_FORMDATA + add_assoc_long(return_value, "file_upload_progress", 1); +#else + add_assoc_long(return_value, "file_upload_progress", 0); +#endif +#if APC_MMAP + add_assoc_stringl(return_value, "memory_type", "mmap", sizeof("mmap")-1, 1); +#else + add_assoc_stringl(return_value, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1); +#endif +#if APC_SEM_LOCKS + add_assoc_stringl(return_value, "locking_type", "IPC semaphore", sizeof("IPC semaphore")-1, 1); +#elif APC_FUTEX_LOCKS + add_assoc_stringl(return_value, "locking_type", "Linux Futex", sizeof("Linux Futex")-1, 1); +#elif APC_PTHREADMUTEX_LOCKS + add_assoc_stringl(return_value, "locking_type", "pthread mutex", sizeof("pthread mutex")-1, 1); +#elif APC_SPIN_LOCKS + add_assoc_stringl(return_value, "locking_type", "spin", sizeof("spin")-1, 1); +#else + add_assoc_stringl(return_value, "locking_type", "file", sizeof("file")-1, 1); +#endif + if(limited) { + apc_cache_free_info(info); + return; + } + + ALLOC_INIT_ZVAL(list); + array_init(list); + + for (p = info->list; p != NULL; p = p->next) { + zval* link; + + ALLOC_INIT_ZVAL(link); + array_init(link); + + if(p->type == APC_CACHE_ENTRY_FILE) { + add_assoc_string(link, "filename", p->data.file.filename, 1); + add_assoc_long(link, "device", p->data.file.device); + add_assoc_long(link, "inode", p->data.file.inode); + add_assoc_string(link, "type", "file", 1); + } else if(p->type == APC_CACHE_ENTRY_USER) { + add_assoc_string(link, "info", p->data.user.info, 1); + add_assoc_long(link, "ttl", (long)p->data.user.ttl); + add_assoc_string(link, "type", "user", 1); + } + add_assoc_long(link, "num_hits", p->num_hits); + add_assoc_long(link, "mtime", p->mtime); + add_assoc_long(link, "creation_time", p->creation_time); + add_assoc_long(link, "deletion_time", p->deletion_time); + add_assoc_long(link, "access_time", p->access_time); + add_assoc_long(link, "ref_count", p->ref_count); + add_assoc_long(link, "mem_size", p->mem_size); + add_next_index_zval(list, link); + } + add_assoc_zval(return_value, "cache_list", list); + + ALLOC_INIT_ZVAL(list); + array_init(list); + + for (p = info->deleted_list; p != NULL; p = p->next) { + zval* link; + + ALLOC_INIT_ZVAL(link); + array_init(link); + + if(p->type == APC_CACHE_ENTRY_FILE) { + add_assoc_string(link, "filename", p->data.file.filename, 1); + add_assoc_long(link, "device", p->data.file.device); + add_assoc_long(link, "inode", p->data.file.inode); + add_assoc_string(link, "type", "file", 1); + } else if(p->type == APC_CACHE_ENTRY_USER) { + add_assoc_string(link, "info", p->data.user.info, 1); + add_assoc_long(link, "ttl", (long)p->data.user.ttl); + add_assoc_string(link, "type", "user", 1); + } + add_assoc_long(link, "num_hits", p->num_hits); + add_assoc_long(link, "mtime", p->mtime); + add_assoc_long(link, "creation_time", p->creation_time); + add_assoc_long(link, "deletion_time", p->deletion_time); + add_assoc_long(link, "access_time", p->access_time); + add_assoc_long(link, "ref_count", p->ref_count); + add_assoc_long(link, "mem_size", p->mem_size); + add_next_index_zval(list, link); + } + add_assoc_zval(return_value, "deleted_list", list); + + apc_cache_free_info(info); +} +/* }}} */ + +/* {{{ proto void apc_clear_cache() */ +PHP_FUNCTION(apc_clear_cache) +{ + char *cache_type; + int ct_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache_type, &ct_len) == FAILURE) { + return; + } + + if(ZEND_NUM_ARGS()) { + if(!strcasecmp(cache_type,"user")) { + apc_cache_clear(apc_user_cache); + RETURN_TRUE; + } + } + apc_cache_clear(apc_cache); +} +/* }}} */ + +/* {{{ proto array apc_sma_info([bool limited]) */ +PHP_FUNCTION(apc_sma_info) +{ + apc_sma_info_t* info; + zval* block_lists; + int i; + zend_bool limited = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &limited) == FAILURE) { + return; + } + + info = apc_sma_info(limited); + + if(!info) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC SMA info available. Perhaps APC is disabled via apc.enabled?"); + RETURN_FALSE; + } + + array_init(return_value); + add_assoc_long(return_value, "num_seg", info->num_seg); + add_assoc_long(return_value, "seg_size", info->seg_size); + add_assoc_long(return_value, "avail_mem", apc_sma_get_avail_mem()); + + if(limited) { + apc_sma_free_info(info); + return; + } + +#if ALLOC_DISTRIBUTION + { + size_t *adist = apc_sma_get_alloc_distribution(); + zval* list; + ALLOC_INIT_ZVAL(list); + array_init(list); + for(i=0; i<30; i++) { + add_next_index_long(list, adist[i]); + } + add_assoc_zval(return_value, "adist", list); + } +#endif + ALLOC_INIT_ZVAL(block_lists); + array_init(block_lists); + + for (i = 0; i < info->num_seg; i++) { + apc_sma_link_t* p; + zval* list; + + ALLOC_INIT_ZVAL(list); + array_init(list); + + for (p = info->list[i]; p != NULL; p = p->next) { + zval* link; + + ALLOC_INIT_ZVAL(link); + array_init(link); + + add_assoc_long(link, "size", p->size); + add_assoc_long(link, "offset", p->offset); + add_next_index_zval(list, link); + } + add_next_index_zval(block_lists, list); + } + add_assoc_zval(return_value, "block_lists", block_lists); + apc_sma_free_info(info); +} +/* }}} */ + +/* {{{ _apc_store */ +int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC) { + apc_cache_entry_t *entry; + apc_cache_key_t key; + time_t t; + size_t mem_size = 0; + +#if PHP_API_VERSION < 20041225 +#if HAVE_APACHE && defined(APC_PHP4_STAT) + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif +#else + t = sapi_get_request_time(TSRMLS_C); +#endif + + if(!APCG(enabled)) return 0; + + HANDLE_BLOCK_INTERRUPTIONS(); + + APCG(mem_size_ptr) = &mem_size; + if (!(entry = apc_cache_make_user_entry(strkey, strkey_len + 1, val, ttl))) { + APCG(mem_size_ptr) = NULL; + apc_cache_expunge(apc_cache,t); + apc_cache_expunge(apc_user_cache,t); + HANDLE_UNBLOCK_INTERRUPTIONS(); + return 0; + } + + if (!apc_cache_make_user_key(&key, strkey, strkey_len + 1, t)) { + APCG(mem_size_ptr) = NULL; + apc_cache_free_entry(entry); + apc_cache_expunge(apc_cache,t); + apc_cache_expunge(apc_user_cache,t); + HANDLE_UNBLOCK_INTERRUPTIONS(); + return 0; + } + + if (!apc_cache_user_insert(apc_user_cache, key, entry, t, exclusive TSRMLS_CC)) { + APCG(mem_size_ptr) = NULL; + apc_cache_free_entry(entry); + apc_cache_expunge(apc_cache,t); + apc_cache_expunge(apc_user_cache,t); + HANDLE_UNBLOCK_INTERRUPTIONS(); + return 0; + } + + APCG(mem_size_ptr) = NULL; + + HANDLE_UNBLOCK_INTERRUPTIONS(); + + return 1; +} +/* }}} */ + +/* {{{ proto int apc_store(string key, zval var [, ttl ]) + */ +PHP_FUNCTION(apc_store) { + zval *val; + char *strkey; + int strkey_len; + long ttl = 0L; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 0 TSRMLS_CC)) RETURN_TRUE; + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto int apc_add(string key, zval var [, ttl ]) + */ +PHP_FUNCTION(apc_add) { + zval *val; + char *strkey; + int strkey_len; + long ttl = 0L; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 1 TSRMLS_CC)) RETURN_TRUE; + RETURN_FALSE; +} +/* }}} */ + +void *apc_erealloc_wrapper(void *ptr, size_t size) { + return _erealloc(ptr, size, 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); +} + +/* {{{ RETURN_ZVAL for php4 */ +#if !defined(ZEND_ENGINE_2) && !defined(RETURN_ZVAL) +#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; } +#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor) +#define ZVAL_ZVAL(z, zv, copy, dtor) { \ + int is_ref, refcount; \ + is_ref = (z)->is_ref; \ + refcount = (z)->refcount; \ + *(z) = *(zv); \ + if (copy) { \ + zval_copy_ctor(z); \ + } \ + if (dtor) { \ + if (!copy) { \ + ZVAL_NULL(zv); \ + } \ + zval_ptr_dtor(&zv); \ + } \ + (z)->is_ref = is_ref; \ + (z)->refcount = refcount; \ + } +#endif +/* }}} */ + +/* {{{ proto mixed apc_fetch(mixed key) + */ +PHP_FUNCTION(apc_fetch) { + zval *key; + HashTable *hash; + HashPosition hpos; + zval **hentry; + zval *result; + zval *result_entry; + char *strkey; + int strkey_len; + apc_cache_entry_t* entry; + time_t t; + + if(!APCG(enabled)) RETURN_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) { + return; + } + +#if PHP_API_VERSION < 20041225 +#if HAVE_APACHE && defined(APC_PHP4_STAT) + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif +#else + t = sapi_get_request_time(TSRMLS_C); +#endif + + if(Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) { + convert_to_string(key); + } + + if(Z_TYPE_P(key) == IS_STRING) { + strkey = Z_STRVAL_P(key); + strkey_len = Z_STRLEN_P(key); + if(!strkey_len) RETURN_FALSE; + entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t); + if(entry) { + /* deep-copy returned shm zval to emalloc'ed return_value */ + apc_cache_fetch_zval(return_value, entry->data.user.val, apc_php_malloc, apc_php_free); + apc_cache_release(apc_user_cache, entry); + } else { + RETURN_FALSE; + } + } else if(Z_TYPE_P(key) == IS_ARRAY) { + hash = Z_ARRVAL_P(key); + MAKE_STD_ZVAL(result); + array_init(result); + zend_hash_internal_pointer_reset_ex(hash, &hpos); + while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { + if(Z_TYPE_PP(hentry) != IS_STRING) { + apc_wprint("apc_fetch() expects a string or array of strings."); + RETURN_FALSE; + } + entry = apc_cache_user_find(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1, t); + if(entry) { + /* deep-copy returned shm zval to emalloc'ed return_value */ + MAKE_STD_ZVAL(result_entry); + apc_cache_fetch_zval(result_entry, entry->data.user.val, apc_php_malloc, apc_php_free); + apc_cache_release(apc_user_cache, entry); + zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1, &result_entry, sizeof(zval*), NULL); + } /* don't set values we didn't find */ + zend_hash_move_forward_ex(hash, &hpos); + } + RETURN_ZVAL(result, 0, 1); + } else { + apc_wprint("apc_fetch() expects a string or array of strings."); + RETURN_FALSE; + } + + return; +} +/* }}} */ + +/* {{{ proto mixed apc_delete(string key) + */ +PHP_FUNCTION(apc_delete) { + char *strkey; + int strkey_len; + + if(!APCG(enabled)) RETURN_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &strkey, &strkey_len) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + if(apc_cache_user_delete(apc_user_cache, strkey, strkey_len + 1)) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} +/* }}} */ + +static void _apc_define_constants(zval *constants, zend_bool case_sensitive TSRMLS_DC) { + char *const_key; + unsigned int const_key_len; + zval **entry; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(constants), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(constants), (void**)&entry, &pos) == SUCCESS) { + zend_constant c; + int key_type; + ulong num_key; + + key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(constants), &const_key, &const_key_len, &num_key, 0, &pos); + if(key_type != HASH_KEY_IS_STRING) { + zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); + continue; + } + switch(Z_TYPE_PP(entry)) { + case IS_LONG: + case IS_DOUBLE: + case IS_STRING: + case IS_BOOL: + case IS_RESOURCE: + case IS_NULL: + break; + default: + zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); + continue; + } + c.value = **entry; + zval_copy_ctor(&c.value); + c.flags = case_sensitive; + c.name = zend_strndup(const_key, const_key_len); + c.name_len = const_key_len; +#ifdef ZEND_ENGINE_2 + c.module_number = PHP_USER_CONSTANT; +#endif + zend_register_constant(&c TSRMLS_CC); + + zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); + } +} + +/* {{{ proto mixed apc_define_constants(string key, array constants [,bool case-sensitive]) + */ +PHP_FUNCTION(apc_define_constants) { + char *strkey; + int strkey_len; + zval *constants = NULL; + zend_bool case_sensitive = 1; + int argc = ZEND_NUM_ARGS(); + + if (zend_parse_parameters(argc TSRMLS_CC, "sa|b", &strkey, &strkey_len, &constants, &case_sensitive) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + _apc_define_constants(constants, case_sensitive TSRMLS_CC); + if(_apc_store(strkey, strkey_len, constants, 0, 0 TSRMLS_CC)) RETURN_TRUE; + RETURN_FALSE; +} /* }}} */ + +/* {{{ proto mixed apc_load_constants(string key [, bool case-sensitive]) + */ +PHP_FUNCTION(apc_load_constants) { + char *strkey; + int strkey_len; + apc_cache_entry_t* entry; + time_t t; + zend_bool case_sensitive = 1; + + if(!APCG(enabled)) RETURN_FALSE; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &strkey, &strkey_len, &case_sensitive) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + +#if PHP_API_VERSION < 20041225 +#if HAVE_APACHE && defined(APC_PHP4_STAT) + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif +#else + t = sapi_get_request_time(TSRMLS_C); +#endif + + entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t); + + if(entry) { + _apc_define_constants(entry->data.user.val, case_sensitive TSRMLS_CC); + apc_cache_release(apc_user_cache, entry); + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto boolean apc_compile_file(string filename) + */ +PHP_FUNCTION(apc_compile_file) { + char *filename; + int filename_len; + zend_file_handle file_handle; + zend_op_array *op_array; + long slam_defense = 0; + char** filters = NULL; + zend_bool cache_by_default = 1; + HashTable cg_function_table, cg_class_table, eg_function_table, eg_class_table; + HashTable *cg_orig_function_table, *cg_orig_class_table, *eg_orig_function_table, *eg_orig_class_table; + + if(!APCG(enabled)) RETURN_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { + return; + } + + if(!filename) RETURN_FALSE; + + /* reset slam defense, filters, and cache_by_default */ + slam_defense = APCG(slam_defense); + APCG(slam_defense) = 0; + + filters = APCG(filters); + APCG(filters) = NULL; + + cache_by_default = APCG(cache_by_default); + APCG(cache_by_default) = 1; + + /* Replace function/class tables to avoid namespace conflicts */ + zend_hash_init_ex(&cg_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); + cg_orig_function_table = CG(function_table); + CG(function_table) = &cg_function_table; + zend_hash_init_ex(&cg_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); + cg_orig_class_table = CG(class_table); + CG(class_table) = &cg_class_table; + eg_orig_function_table = EG(function_table); + EG(function_table) = CG(function_table); + eg_orig_class_table = EG(class_table); + EG(class_table) = CG(class_table); + APCG(force_file_update) = 1; + + /* Compile the file, loading it into the cache */ + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.filename = filename; + file_handle.free_filename = 0; + file_handle.opened_path = NULL; + zend_try { + op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC); + } zend_catch { + apc_wprint("Error compiling %s in apc_compile_file.", filename); + op_array = NULL; + } zend_end_try(); + + /* Return class/function tables to previous states, destroy temp tables */ + APCG(force_file_update) = 0; + CG(function_table) = cg_orig_function_table; + zend_hash_destroy(&cg_function_table); + CG(class_table) = cg_orig_class_table; + zend_hash_destroy(&cg_class_table); + EG(function_table) = eg_orig_function_table; + EG(class_table) = eg_orig_class_table; + + /* Restore global settings */ + APCG(slam_defense) = slam_defense; + APCG(filters) = filters; + APCG(cache_by_default) = cache_by_default; + + if(op_array == NULL) { RETURN_FALSE; } + + /* Free up everything */ + zend_destroy_file_handle(&file_handle TSRMLS_CC); +#ifdef ZEND_ENGINE_2 + destroy_op_array(op_array TSRMLS_CC); +#else + destroy_op_array(op_array); +#endif + efree(op_array); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ apc_functions[] */ +function_entry apc_functions[] = { + PHP_FE(apc_cache_info, NULL) + PHP_FE(apc_clear_cache, NULL) + PHP_FE(apc_sma_info, NULL) + PHP_FE(apc_store, NULL) + PHP_FE(apc_fetch, NULL) + PHP_FE(apc_delete, NULL) + PHP_FE(apc_define_constants, NULL) + PHP_FE(apc_load_constants, NULL) + PHP_FE(apc_compile_file, NULL) + PHP_FE(apc_add, NULL) + {NULL, NULL, NULL} +}; +/* }}} */ + +/* {{{ module definition structure */ + +zend_module_entry apc_module_entry = { + STANDARD_MODULE_HEADER, + "apc", + apc_functions, + PHP_MINIT(apc), + PHP_MSHUTDOWN(apc), + PHP_RINIT(apc), + PHP_RSHUTDOWN(apc), + PHP_MINFO(apc), + APC_VERSION, + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_APC +ZEND_GET_MODULE(apc) +#endif +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */