Changes of Revision 13
[-] | Changed | php5-APC.changes |
1
2 ------------------------------------------------------------------- 3 +Mon May 16 18:55:04 UTC 2011 - cs@linux-administrator.com 4 + 5 +- update to release 3.1.9 6 + 7 +------------------------------------------------------------------- 8 Fri May 6 20:10:56 UTC 2011 - cs@linux-administrator.com 9 10 - update to release 3.1.8 11 |
||
[-] | Changed | php5-APC.spec ^ |
10 1
2 %define php_version %(php-config --version 2>/dev/null) 3 # 4 Name: php5-APC 5 -Version: 3.1.8 6 +Version: 3.1.9 7 Release: 0 8 # 9 License: Other/See package 10 |
||
[+] | Deleted | APC-3.1.8.tar.bz2/APC-3.1.8/apc_cache.c ^ |
@@ -1,1380 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | APC | - +----------------------------------------------------------------------+ - | Copyright (c) 2006-2011 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 <dcowgill@communityconnect.com> | - | Rasmus Lerdorf <rasmus@php.net> | - | Arun C. Murthy <arunc@yahoo-inc.com> | - | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> | - +----------------------------------------------------------------------+ - - 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: apc_cache.c 309488 2011-03-20 23:59:42Z pajoye $ */ - -#include "apc_cache.h" -#include "apc_zend.h" -#include "apc_sma.h" -#include "apc_globals.h" -#include "SAPI.h" -#include "TSRM.h" -#include "ext/standard/md5.h" - -/* TODO: rehash when load factor exceeds threshold */ - -#define CHECK(p) { if ((p) == NULL) return NULL; } - -/* {{{ key_equals */ -#define key_equals(a, b) (a.inode==b.inode && a.device==b.device) -/* }}} */ - -static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC); - -/* {{{ hash */ -static unsigned long hash(apc_cache_key_t key) -{ - return (unsigned long)(key.data.file.device + key.data.file.inode); -} -/* }}} */ - -/* {{{ string_nhash_8 */ -#define string_nhash_8(s,len) (unsigned long)(zend_inline_hash_func((s), len)) -/* }}} */ - -/* {{{ murmurhash */ -#if 0 -static inline unsigned long murmurhash(const char *skey, size_t keylen) -{ - const long m = 0x7fd652ad; - const long r = 16; - unsigned int h = 0xdeadbeef; - - while(keylen >= 4) - { - h += *(unsigned int*)skey; - h *= m; - h ^= h >> r; - - skey += 4; - keylen -= 4; - } - - switch(keylen) - { - case 3: - h += skey[2] << 16; - case 2: - h += skey[1] << 8; - case 1: - h += skey[0]; - h *= m; - h ^= h >> r; - }; - - h *= m; - h ^= h >> 10; - h *= m; - h ^= h >> 17; - - return h; -} -#endif -/* }}} */ - - -/* {{{ make_prime */ -static int const primes[] = { - 257, /* 256 */ - 521, /* 512 */ - 1031, /* 1024 */ - 2053, /* 2048 */ - 3079, /* 3072 */ - 4099, /* 4096 */ - 5147, /* 5120 */ - 6151, /* 6144 */ - 7177, /* 7168 */ - 8209, /* 8192 */ - 9221, /* 9216 */ -10243, /* 10240 */ -11273, /* 11264 */ -12289, /* 12288 */ -13313, /* 13312 */ -14341, /* 14336 */ -15361, /* 15360 */ -16411, /* 16384 */ -17417, /* 17408 */ -18433, /* 18432 */ -19457, /* 19456 */ -0 /* sentinel */ -}; - -static int make_prime(int n) -{ - int *k = (int*)primes; - while(*k) { - if((*k) > n) return *k; - k++; - } - return *(k-1); -} -/* }}} */ - -/* {{{ make_slot */ -slot_t* make_slot(apc_cache_key_t *key, apc_cache_entry_t* value, slot_t* next, time_t t TSRMLS_DC) -{ - slot_t* p = apc_pool_alloc(value->pool, sizeof(slot_t)); - - if (!p) return NULL; - - if(key->type == APC_CACHE_KEY_USER) { - char *identifier = (char*) apc_pmemcpy(key->data.user.identifier, key->data.user.identifier_len, value->pool TSRMLS_CC); - if (!identifier) { - return NULL; - } - key->data.user.identifier = identifier; - } else if(key->type == APC_CACHE_KEY_FPFILE) { - char *fullpath = (char*) apc_pstrdup(key->data.fpfile.fullpath, value->pool TSRMLS_CC); - if (!fullpath) { - return NULL; - } - key->data.fpfile.fullpath = fullpath; - } - p->key = key[0]; - p->value = value; - p->next = next; - p->num_hits = 0; - p->creation_time = t; - p->access_time = t; - p->deletion_time = 0; - return p; -} -/* }}} */ - -/* {{{ free_slot */ -static void free_slot(slot_t* slot TSRMLS_DC) -{ - apc_pool_destroy(slot->value->pool TSRMLS_CC); -} -/* }}} */ - -/* {{{ remove_slot */ -static void remove_slot(apc_cache_t* cache, slot_t** slot TSRMLS_DC) -{ - slot_t* dead = *slot; - *slot = (*slot)->next; - - cache->header->mem_size -= dead->value->mem_size; - CACHE_FAST_DEC(cache, cache->header->num_entries); - if (dead->value->ref_count <= 0) { - free_slot(dead TSRMLS_CC); - } - else { - dead->next = cache->header->deleted_list; - dead->deletion_time = time(0); - cache->header->deleted_list = dead; - } -} -/* }}} */ - -/* {{{ process_pending_removals */ -static void process_pending_removals(apc_cache_t* cache TSRMLS_DC) -{ - slot_t** slot; - time_t now; - - /* This function scans the list of removed cache entries and deletes any - * entry whose reference count is zero (indicating that it is no longer - * being executed) or that has been on the pending list for more than - * cache->gc_ttl seconds (we issue a warning in the latter case). - */ - - if (!cache->header->deleted_list) - return; - - slot = &cache->header->deleted_list; - now = time(0); - - while (*slot != NULL) { - int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0; - - if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) { - slot_t* dead = *slot; - - if (dead->value->ref_count > 0) { - switch(dead->value->type) { - case APC_CACHE_ENTRY_FILE: - apc_debug("GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds" TSRMLS_CC, - dead->value->data.file.filename, dead->key.data.file.device, dead->key.data.file.inode, gc_sec); - break; - case APC_CACHE_ENTRY_USER: - apc_debug("GC cache entry '%s' was on gc-list for %d seconds" TSRMLS_CC, dead->value->data.user.info, gc_sec); - break; - } - } - *slot = dead->next; - free_slot(dead TSRMLS_CC); - } - else { - slot = &(*slot)->next; - } - } -} -/* }}} */ - -/* {{{ prevent_garbage_collection */ -static void prevent_garbage_collection(apc_cache_entry_t* entry) -{ - /* set reference counts on zend objects to an arbitrarily high value to - * prevent garbage collection after execution */ - - enum { BIG_VALUE = 1000 }; - - if(entry->data.file.op_array) { - entry->data.file.op_array->refcount[0] = BIG_VALUE; - } - if (entry->data.file.functions) { - int i; - apc_function_t* fns = entry->data.file.functions; - for (i=0; fns[i].function != NULL; i++) { - *(fns[i].function->op_array.refcount) = BIG_VALUE; - } - } - if (entry->data.file.classes) { - int i; - apc_class_t* classes = entry->data.file.classes; - for (i=0; classes[i].class_entry != NULL; i++) { - classes[i].class_entry->refcount = BIG_VALUE; - } - } -} -/* }}} */ - -/* {{{ apc_cache_create */ -apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC) -{ - apc_cache_t* cache; - int cache_size; - int num_slots; - - num_slots = make_prime(size_hint > 0 ? size_hint : 2000); - - cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t) TSRMLS_CC); - cache_size = sizeof(cache_header_t) + num_slots*sizeof(slot_t*); - - cache->shmaddr = apc_sma_malloc(cache_size TSRMLS_CC); - if(!cache->shmaddr) { - apc_error("Unable to allocate shared memory for cache structures. (Perhaps your shared memory size isn't large enough?). " TSRMLS_CC); - return NULL; - } - memset(cache->shmaddr, 0, cache_size); - - cache->header = (cache_header_t*) cache->shmaddr; - cache->header->num_hits = 0; - cache->header->num_misses = 0; - cache->header->deleted_list = NULL; - cache->header->start_time = time(NULL); - cache->header->expunges = 0; - cache->header->busy = 0; - - cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(cache_header_t)); - cache->num_slots = num_slots; - cache->gc_ttl = gc_ttl; - cache->ttl = ttl; - CREATE_LOCK(cache->header->lock); -#if NONBLOCKING_LOCK_AVAILABLE - CREATE_LOCK(cache->header->wrlock); -#endif - memset(cache->slots, 0, sizeof(slot_t*)*num_slots); - cache->expunge_cb = apc_cache_expunge; - cache->has_lock = 0; - - return cache; -} -/* }}} */ - -/* {{{ apc_cache_destroy */ -void apc_cache_destroy(apc_cache_t* cache TSRMLS_DC) -{ - DESTROY_LOCK(cache->header->lock); -#ifdef NONBLOCKING_LOCK_AVAILABLE - DESTROY_LOCK(cache->header->wrlock); -#endif - apc_efree(cache TSRMLS_CC); -} -/* }}} */ - -/* {{{ apc_cache_clear */ -void apc_cache_clear(apc_cache_t* cache TSRMLS_DC) -{ - int i; - - if(!cache) return; - - CACHE_LOCK(cache); - cache->header->busy = 1; - cache->header->num_hits = 0; - cache->header->num_misses = 0; - cache->header->start_time = time(NULL); - cache->header->expunges = 0; - - for (i = 0; i < cache->num_slots; i++) { - slot_t* p = cache->slots[i]; - while (p) { - remove_slot(cache, &p TSRMLS_CC); - } - cache->slots[i] = NULL; - } - - memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); - - cache->header->busy = 0; - CACHE_UNLOCK(cache); -} -/* }}} */ - -/* {{{ apc_cache_expunge */ -static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC) -{ - int i; - time_t t; - - t = apc_time(); - - if(!cache) return; - - if(!cache->ttl) { - /* - * If cache->ttl is not set, we wipe out the entire cache when - * we run out of space. - */ - CACHE_SAFE_LOCK(cache); - process_pending_removals(cache TSRMLS_CC); - if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) { - /* probably a queued up expunge, we don't need to do this */ - CACHE_SAFE_UNLOCK(cache); - return; - } - cache->header->busy = 1; - CACHE_FAST_INC(cache, cache->header->expunges); -clear_all: - for (i = 0; i < cache->num_slots; i++) { - slot_t* p = cache->slots[i]; - while (p) { - remove_slot(cache, &p TSRMLS_CC); - } - cache->slots[i] = NULL; - } - memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); - cache->header->busy = 0; - CACHE_SAFE_UNLOCK(cache); - } else { - slot_t **p; - /* - * If the ttl for the cache is set we walk through and delete stale - * entries. For the user cache that is slightly confusing since - * we have the individual entry ttl's we can look at, but that would be - * too much work. So if you want the user cache expunged, set a high - * default apc.user_ttl and still provide a specific ttl for each entry - * on insert - */ - - CACHE_SAFE_LOCK(cache); - process_pending_removals(cache TSRMLS_CC); - if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) { - /* probably a queued up expunge, we don't need to do this */ - CACHE_SAFE_UNLOCK(cache); - return; - } - cache->header->busy = 1; - CACHE_FAST_INC(cache, cache->header->expunges); - for (i = 0; i < cache->num_slots; i++) { - p = &cache->slots[i]; - while(*p) { - /* - * For the user cache we look at the individual entry ttl values - * and if not set fall back to the default ttl for the user cache - */ - if((*p)->value->type == APC_CACHE_ENTRY_USER) { - if((*p)->value->data.user.ttl) { - if((time_t) ((*p)->creation_time + (*p)->value->data.user.ttl) < t) { - remove_slot(cache, p TSRMLS_CC); - continue; - } - } else if(cache->ttl) { - if((*p)->creation_time + cache->ttl < t) { - remove_slot(cache, p TSRMLS_CC); - continue; - } - } - } else if((*p)->access_time < (t - cache->ttl)) { - remove_slot(cache, p TSRMLS_CC); - continue; - } - p = &(*p)->next; - } - } - - if (!apc_sma_get_avail_size(size)) { - /* TODO: re-do this to remove goto across locked sections */ - goto clear_all; - } - memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); - cache->header->busy = 0; - CACHE_SAFE_UNLOCK(cache); - } -} -/* }}} */ - -/* {{{ apc_cache_insert */ -static inline int _apc_cache_insert(apc_cache_t* cache, - apc_cache_key_t key, - apc_cache_entry_t* value, - apc_context_t* ctxt, - time_t t - TSRMLS_DC) -{ - slot_t** slot; - - if (!value) { - return 0; - } - - apc_debug("Inserting [%s]\n" TSRMLS_CC, value->data.file.filename); - - process_pending_removals(cache TSRMLS_CC); - - slot = &cache->slots[key.h % cache->num_slots]; - - while(*slot) { - if(key.type == (*slot)->key.type) { - if(key.type == APC_CACHE_KEY_FILE) { - if(key_equals((*slot)->key.data.file, key.data.file)) { - /* If existing slot for the same device+inode is different, remove it and insert the new version */ - if (ctxt->force_update || (*slot)->key.mtime != key.mtime) { - remove_slot(cache, slot TSRMLS_CC); - break; - } - return 0; - } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { - remove_slot(cache, slot TSRMLS_CC); - continue; - } - } else { /* APC_CACHE_KEY_FPFILE */ - if((key.h == (*slot)->key.h) && - !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { - /* Hrm.. it's already here, remove it and insert new one */ - remove_slot(cache, slot TSRMLS_CC); - break; - } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { - remove_slot(cache, slot TSRMLS_CC); - continue; - } - } - } - slot = &(*slot)->next; - } - - if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) { - return -1; - } - - value->mem_size = ctxt->pool->size; - cache->header->mem_size += ctxt->pool->size; - CACHE_FAST_INC(cache, cache->header->num_entries); - CACHE_FAST_INC(cache, cache->header->num_inserts); - - return 1; -} -/* }}} */ - -/* {{{ apc_cache_insert */ -int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t *ctxt, time_t t TSRMLS_DC) -{ - int rval; - CACHE_LOCK(cache); - rval = _apc_cache_insert(cache, key, value, ctxt, t TSRMLS_CC); - CACHE_UNLOCK(cache); - return rval; -} -/* }}} */ - -/* {{{ apc_cache_insert */ -int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys, apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries TSRMLS_DC) -{ - int *rval; - int i; - - rval = emalloc(sizeof(int) * num_entries); - CACHE_LOCK(cache); - for (i=0; i < num_entries; i++) { - if (values[i]) { - ctxt->pool = values[i]->pool; - rval[i] = _apc_cache_insert(cache, keys[i], values[i], ctxt, t TSRMLS_CC); - } - } - CACHE_UNLOCK(cache); - return rval; -} -/* }}} */ - - -/* {{{ apc_cache_user_insert */ -int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC) -{ - slot_t** slot; - unsigned int keylen = key.data.user.identifier_len; - apc_keyid_t *lastkey = &cache->header->lastkey; - - if (!value) { - return 0; - } - - if(apc_cache_busy(cache)) { - /* cache cleanup in progress, do not wait */ - return 0; - } - - if(apc_cache_is_last_key(cache, &key, t TSRMLS_CC)) { - /* potential cache slam */ - return 0; - } - - CACHE_LOCK(cache); - - memset(lastkey, 0, sizeof(apc_keyid_t)); - - lastkey->h = key.h; - lastkey->keylen = keylen; - lastkey->mtime = t; -#ifdef ZTS - lastkey->tid = tsrm_thread_id(); -#else - lastkey->pid = getpid(); -#endif - - /* we do not reset lastkey after the insert. Whether it is inserted - * or not, another insert in the same second is always a bad idea. - */ - - process_pending_removals(cache TSRMLS_CC); - - slot = &cache->slots[key.h % cache->num_slots]; - - while (*slot) { - if (((*slot)->key.h == key.h) && - (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, keylen))) { - /* - * At this point we have found the user cache entry. If we are doing - * an exclusive insert (apc_add) we are going to bail right away if - * the user entry already exists and it has no ttl, or - * there is a ttl and the entry has not timed out yet. - */ - if(exclusive && ( !(*slot)->value->data.user.ttl || - ( (*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t ) - ) ) { - goto fail; - } - remove_slot(cache, slot TSRMLS_CC); - break; - } else - /* - * This is a bit nasty. The idea here is to do runtime cleanup of the linked list of - * slot entries so we don't always have to skip past a bunch of stale entries. We check - * for staleness here and get rid of them by first checking to see if the cache has a global - * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly - * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl - */ - if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) || - ((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) { - remove_slot(cache, slot TSRMLS_CC); - continue; - } - slot = &(*slot)->next; - } - - if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) { - goto fail; - } - - value->mem_size = ctxt->pool->size; - cache->header->mem_size += ctxt->pool->size; - - CACHE_FAST_INC(cache, cache->header->num_entries); - CACHE_FAST_INC(cache, cache->header->num_inserts); - - CACHE_UNLOCK(cache); - - return 1; - -fail: - CACHE_UNLOCK(cache); - - return 0; -} -/* }}} */ - -/* {{{ apc_cache_find_slot */ -slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC) -{ - slot_t** slot; - volatile slot_t* retval = NULL; - - CACHE_RDLOCK(cache); - if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots]; - else slot = &cache->slots[key.h % cache->num_slots]; - - while (*slot) { - if(key.type == (*slot)->key.type) { - if(key.type == APC_CACHE_KEY_FILE) { - if(key_equals((*slot)->key.data.file, key.data.file)) { - if((*slot)->key.mtime != key.mtime) { - #if (USE_READ_LOCKS == 0) - /* this is merely a memory-friendly optimization, if we do have a write-lock - * might as well move this to the deleted_list right-away. Otherwise an insert - * of the same key wil do it (or an expunge, *eventually*). - */ - remove_slot(cache, slot TSRMLS_CC); - #endif - CACHE_SAFE_INC(cache, cache->header->num_misses); - CACHE_RDUNLOCK(cache); - return NULL; - } - CACHE_SAFE_INC(cache, (*slot)->num_hits); - CACHE_SAFE_INC(cache, (*slot)->value->ref_count); - (*slot)->access_time = t; - prevent_garbage_collection((*slot)->value); - CACHE_FAST_INC(cache, cache->header->num_hits); - retval = *slot; - CACHE_RDUNLOCK(cache); - return (slot_t*)retval; - } - } else { /* APC_CACHE_KEY_FPFILE */ - if(((*slot)->key.h == key.h) && - !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { - /* TTL Check ? */ - CACHE_SAFE_INC(cache, (*slot)->num_hits); - CACHE_SAFE_INC(cache, (*slot)->value->ref_count); - (*slot)->access_time = t; - prevent_garbage_collection((*slot)->value); - CACHE_FAST_INC(cache, cache->header->num_hits); - retval = *slot; - CACHE_RDUNLOCK(cache); - return (slot_t*)retval; - } - } - } - slot = &(*slot)->next; - } - CACHE_FAST_INC(cache, cache->header->num_misses); - CACHE_RDUNLOCK(cache); - return NULL; -} -/* }}} */ - -/* {{{ apc_cache_find */ -apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC) -{ - slot_t * slot = apc_cache_find_slot(cache, key, t TSRMLS_CC); - apc_debug("apc_cache_find [%i]\n" TSRMLS_CC, key.h); - return (slot) ? slot->value : NULL; -} -/* }}} */ - -/* {{{ apc_cache_user_find */ -apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC) -{ - slot_t** slot; - volatile apc_cache_entry_t* value = NULL; - unsigned long h; - - if(apc_cache_busy(cache)) - { - /* cache cleanup in progress */ - return NULL; - } - - CACHE_RDLOCK(cache); - - h = string_nhash_8(strkey, keylen); - - slot = &cache->slots[h % cache->num_slots]; - - while (*slot) { - if ((h == (*slot)->key.h) && - !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { - /* Check to make sure this entry isn't expired by a hard TTL */ - if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) { - #if (USE_READ_LOCKS == 0) - /* this is merely a memory-friendly optimization, if we do have a write-lock - * might as well move this to the deleted_list right-away. Otherwise an insert - * of the same key wil do it (or an expunge, *eventually*). - */ - remove_slot(cache, slot TSRMLS_CC); - #endif - CACHE_FAST_INC(cache, cache->header->num_misses); - CACHE_RDUNLOCK(cache); - return NULL; - } - /* Otherwise we are fine, increase counters and return the cache entry */ - CACHE_SAFE_INC(cache, (*slot)->num_hits); - CACHE_SAFE_INC(cache, (*slot)->value->ref_count); - (*slot)->access_time = t; - - CACHE_FAST_INC(cache, cache->header->num_hits); - value = (*slot)->value; - CACHE_RDUNLOCK(cache); - return (apc_cache_entry_t*)value; - } - slot = &(*slot)->next; - } - - CACHE_FAST_INC(cache, cache->header->num_misses); - CACHE_RDUNLOCK(cache); - return NULL; -} -/* }}} */ - -/* {{{ apc_cache_user_exists */ -apc_cache_entry_t* apc_cache_user_exists(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC) -{ - slot_t** slot; - volatile apc_cache_entry_t* value = NULL; - unsigned long h; - - if(apc_cache_busy(cache)) - { - /* cache cleanup in progress */ - return NULL; - } - - CACHE_RDLOCK(cache); - - h = string_nhash_8(strkey, keylen); - - slot = &cache->slots[h % cache->num_slots]; - - while (*slot) { - if ((h == (*slot)->key.h) && - !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { - /* Check to make sure this entry isn't expired by a hard TTL */ - if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) { - CACHE_UNLOCK(cache); - return NULL; - } - /* Return the cache entry ptr */ - value = (*slot)->value; - CACHE_RDUNLOCK(cache); - return (apc_cache_entry_t*)value; - } - slot = &(*slot)->next; - } - CACHE_RDUNLOCK(cache); - return NULL; -} -/* }}} */ - -/* {{{ apc_cache_user_update */ -int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen, apc_cache_updater_t updater, void* data TSRMLS_DC) -{ - slot_t** slot; - int retval; - unsigned long h; - - if(apc_cache_busy(cache)) - { - /* cache cleanup in progress */ - return 0; - } - - CACHE_LOCK(cache); - - h = string_nhash_8(strkey, keylen); - slot = &cache->slots[h % cache->num_slots]; - - while (*slot) { - if ((h == (*slot)->key.h) && - !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { - switch(Z_TYPE_P((*slot)->value->data.user.val) & ~IS_CONSTANT_INDEX) { - case IS_ARRAY: - case IS_CONSTANT_ARRAY: - case IS_OBJECT: - { - if(APCG(serializer)) { - retval = 0; - break; - } else { - /* fall through */ - } - } - /* fall through */ - default: - { - retval = updater(cache, (*slot)->value, data); - (*slot)->key.mtime = apc_time(); - } - break; - } - CACHE_UNLOCK(cache); - return retval; - } - slot = &(*slot)->next; - } - CACHE_UNLOCK(cache); - return 0; -} -/* }}} */ - -/* {{{ apc_cache_user_delete */ -int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC) -{ - slot_t** slot; - unsigned long h; - - CACHE_LOCK(cache); - - h = string_nhash_8(strkey, keylen); - - slot = &cache->slots[h % cache->num_slots]; - - while (*slot) { - if ((h == (*slot)->key.h) && - !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { - remove_slot(cache, slot TSRMLS_CC); - CACHE_UNLOCK(cache); - return 1; - } - slot = &(*slot)->next; - } - - CACHE_UNLOCK(cache); - return 0; -} -/* }}} */ - -/* {{{ apc_cache_delete */ -int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC) -{ - slot_t** slot; - time_t t; - apc_cache_key_t key; - - t = apc_time(); - - /* try to create a cache key; if we fail, give up on caching */ - if (!apc_cache_make_file_key(&key, filename, PG(include_path), t TSRMLS_CC)) { - apc_warning("Could not stat file %s, unable to delete from cache." TSRMLS_CC, filename); - return -1; - } - - CACHE_LOCK(cache); - - if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots]; - else slot = &cache->slots[key.h % cache->num_slots]; - - while(*slot) { - if(key.type == (*slot)->key.type) { - if(key.type == APC_CACHE_KEY_FILE) { - if(key_equals((*slot)->key.data.file, key.data.file)) { - remove_slot(cache, slot TSRMLS_CC); - CACHE_UNLOCK(cache); - return 1; - } - } else { /* APC_CACHE_KEY_FPFILE */ - if(((*slot)->key.h == key.h) && - (!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1))) { - remove_slot(cache, slot TSRMLS_CC); - CACHE_UNLOCK(cache); - return 1; - } - } - } - slot = &(*slot)->next; - } - - memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); - - CACHE_UNLOCK(cache); - return 0; - -} -/* }}} */ - -/* {{{ apc_cache_release */ -void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry TSRMLS_DC) -{ - CACHE_SAFE_DEC(cache, entry->ref_count); -} -/* }}} */ - -/* {{{ apc_cache_make_file_key */ -int apc_cache_make_file_key(apc_cache_key_t* key, - const char* filename, - const char* include_path, - time_t t - TSRMLS_DC) -{ - struct stat *tmp_buf=NULL; - struct apc_fileinfo_t *fileinfo = NULL; - int len; - - assert(key != NULL); - - if (!filename || !SG(request_info).path_translated) { - apc_debug("No filename and no path_translated - bailing\n" TSRMLS_CC); - goto cleanup; - } - - len = strlen(filename); - if(APCG(fpstat)==0) { - if(IS_ABSOLUTE_PATH(filename,len)) { - key->data.fpfile.fullpath = filename; - key->data.fpfile.fullpath_len = len; - key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len); - key->mtime = t; - key->type = APC_CACHE_KEY_FPFILE; - goto success; - } else if(APCG(canonicalize)) { - - fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC); - - if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) { - apc_warning("apc failed to locate %s - bailing" TSRMLS_CC, filename); - goto cleanup; - } - - if(!VCWD_REALPATH(fileinfo->fullpath, APCG(canon_path))) { - apc_warning("realpath failed to canonicalize %s - bailing" TSRMLS_CC, filename); - goto cleanup; - } - - key->data.fpfile.fullpath = APCG(canon_path); - key->data.fpfile.fullpath_len = strlen(APCG(canon_path)); - key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len); - key->mtime = t; - key->type = APC_CACHE_KEY_FPFILE; - goto success; - } - /* fall through to stat mode */ - } - - fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC); - - assert(fileinfo != NULL); - - if(!strcmp(SG(request_info).path_translated, filename)) { - tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */ - } - - if(tmp_buf) { - fileinfo->st_buf.sb = *tmp_buf; - } else { - if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) { - apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC, filename,SG(request_info).path_translated); - goto cleanup; - } - } - - if(APCG(max_file_size) < fileinfo->st_buf.sb.st_size) { - apc_debug("File is too big %s (%d - %ld) - bailing\n" TSRMLS_CC, filename,t,fileinfo->st_buf.sb.st_size); - goto cleanup; - } - - /* - * This is a bit of a hack. - * - * Here I am checking to see if the file is at least 2 seconds old. - * The idea is that if the file is currently being written to then its - * mtime is going to match or at most be 1 second off of the current - * request time and we want to avoid caching files that have not been - * completely written. Of course, people should be using atomic - * mechanisms to push files onto live web servers, but adding this - * tiny safety is easier than educating the world. This is now - * configurable, but the default is still 2 seconds. - */ - if(APCG(file_update_protection) && (t - fileinfo->st_buf.sb.st_mtime < APCG(file_update_protection)) && !APCG(force_file_update)) { - apc_debug("File is too new %s (%d - %d) - bailing\n" TSRMLS_CC,filename,t,fileinfo->st_buf.sb.st_mtime); - goto cleanup; - } - - key->data.file.device = fileinfo->st_buf.sb.st_dev; - key->data.file.inode = fileinfo->st_buf.sb.st_ino; - key->h = (unsigned long) key->data.file.device + (unsigned long) key->data.file.inode; - - /* - * If working with content management systems that like to munge the mtime, - * it might be appropriate to key off of the ctime to be immune to systems - * that try to backdate a template. If the mtime is set to something older - * than the previous mtime of a template we will obviously never see this - * "older" template. At some point the Smarty templating system did this. - * I generally disagree with using the ctime here because you lose the - * ability to warm up new content by saving it to a temporary file, hitting - * it once to cache it and then renaming it into its permanent location so - * set the apc.stat_ctime=true to enable this check. - */ - if(APCG(stat_ctime)) { - key->mtime = (fileinfo->st_buf.sb.st_ctime > fileinfo->st_buf.sb.st_mtime) ? fileinfo->st_buf.sb.st_ctime : fileinfo->st_buf.sb.st_mtime; - } else { - key->mtime = fileinfo->st_buf.sb.st_mtime; - } - key->type = APC_CACHE_KEY_FILE; - -success: - - if(fileinfo != NULL) { - apc_php_free(fileinfo TSRMLS_CC); - } - - return 1; - -cleanup: - - if(fileinfo != NULL) { - apc_php_free(fileinfo TSRMLS_CC); - } - - return 0; -} -/* }}} */ - -/* {{{ apc_cache_make_user_key */ -int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t) -{ - assert(key != NULL); - - if (!identifier) - return 0; - - key->data.user.identifier = identifier; - key->data.user.identifier_len = identifier_len; - key->h = string_nhash_8(key->data.user.identifier, key->data.user.identifier_len); - key->mtime = t; - key->type = APC_CACHE_KEY_USER; - return 1; -} -/* }}} */ - -/* {{{ apc_cache_make_file_entry */ -apc_cache_entry_t* apc_cache_make_file_entry(const char* filename, - zend_op_array* op_array, - apc_function_t* functions, - apc_class_t* classes, - apc_context_t* ctxt - TSRMLS_DC) -{ - apc_cache_entry_t* entry; - apc_pool* pool = ctxt->pool; - - entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t)); - if (!entry) return NULL; - - entry->data.file.filename = apc_pstrdup(filename, pool TSRMLS_CC); - if(!entry->data.file.filename) { - apc_debug("apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n" TSRMLS_CC); - return NULL; - } - apc_debug("apc_cache_make_file_entry: entry->data.file.filename is [%s]\n" TSRMLS_CC,entry->data.file.filename); - entry->data.file.op_array = op_array; - entry->data.file.functions = functions; - entry->data.file.classes = classes; - - entry->data.file.halt_offset = apc_file_halt_offset(filename TSRMLS_CC); - - entry->type = APC_CACHE_ENTRY_FILE; - entry->ref_count = 0; - entry->mem_size = 0; - entry->pool = pool; - return entry; -} -/* }}} */ - -/* {{{ apc_cache_store_zval */ -zval* apc_cache_store_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) -{ - if (Z_TYPE_P(src) == IS_ARRAY) { - /* Maintain a list of zvals we've copied to properly handle recursive structures */ - zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0); - dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); - zend_hash_destroy(&APCG(copied_zvals)); - APCG(copied_zvals).nTableSize=0; - } else { - dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); - } - - - return dst; -} -/* }}} */ - -/* {{{ apc_cache_fetch_zval */ -zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) -{ - if (Z_TYPE_P(src) == IS_ARRAY) { - /* Maintain a list of zvals we've copied to properly handle recursive structures */ - zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0); - dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); - zend_hash_destroy(&APCG(copied_zvals)); - APCG(copied_zvals).nTableSize=0; - } else { - dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); - } - - - return dst; -} -/* }}} */ - -/* {{{ apc_cache_make_user_entry */ -apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, apc_context_t* ctxt, const unsigned int ttl TSRMLS_DC) -{ - apc_cache_entry_t* entry; - apc_pool* pool = ctxt->pool; - - entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t)); - if (!entry) return NULL; - - entry->data.user.info = apc_pmemcpy(info, info_len, pool TSRMLS_CC); - entry->data.user.info_len = info_len; - if(!entry->data.user.info) { - return NULL; - } - entry->data.user.val = apc_cache_store_zval(NULL, val, ctxt TSRMLS_CC); - if(!entry->data.user.val) { - return NULL; - } - INIT_PZVAL(entry->data.user.val); - entry->data.user.ttl = ttl; - entry->type = APC_CACHE_ENTRY_USER; - entry->ref_count = 0; - entry->mem_size = 0; - entry->pool = pool; - return entry; -} -/* }}} */ - -/* {{{ */ -static zval* apc_cache_link_info(apc_cache_t *cache, slot_t* p TSRMLS_DC) -{ - zval *link = NULL; - char md5str[33]; - - ALLOC_INIT_ZVAL(link); - - if(!link) { - return NULL; - } - - array_init(link); - - if(p->value->type == APC_CACHE_ENTRY_FILE) { - add_assoc_string(link, "type", "file", 1); - if(p->key.type == APC_CACHE_KEY_FILE) { - - #ifdef PHP_WIN32 - { - char buf[20]; - sprintf(buf, "%I64d", p->key.data.file.device); - add_assoc_string(link, "device", buf, 1); - - sprintf(buf, "%I64d", p->key.data.file.inode); - add_assoc_string(link, "inode", buf, 1); - } - #else - add_assoc_long(link, "device", p->key.data.file.device); - add_assoc_long(link, "inode", p->key.data.file.inode); - #endif - - add_assoc_string(link, "filename", p->value->data.file.filename, 1); - } else { /* This is a no-stat fullpath file entry */ - add_assoc_long(link, "device", 0); - add_assoc_long(link, "inode", 0); - add_assoc_string(link, "filename", (char*)p->key.data.fpfile.fullpath, 1); - } - if (APCG(file_md5)) { - make_digest(md5str, p->key.md5); - add_assoc_string(link, "md5", md5str, 1); - } - } else if(p->value->type == APC_CACHE_ENTRY_USER) { - add_assoc_stringl(link, "info", p->value->data.user.info, p->value->data.user.info_len-1, 1); - add_assoc_long(link, "ttl", (long)p->value->data.user.ttl); - add_assoc_string(link, "type", "user", 1); - } - - add_assoc_double(link, "num_hits", (double)p->num_hits); - add_assoc_long(link, "mtime", p->key.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->value->ref_count); - add_assoc_long(link, "mem_size", p->value->mem_size); - - return link; -} -/* }}} */ - -/* {{{ apc_cache_info */ -zval* apc_cache_info(apc_cache_t* cache, zend_bool limited TSRMLS_DC) -{ - zval *info = NULL; - zval *list = NULL; - zval *deleted_list = NULL; - zval *slots = NULL; - slot_t* p; - int i, j; - - if(!cache) return NULL; - - CACHE_RDLOCK(cache); - - ALLOC_INIT_ZVAL(info); - - if(!info) { - CACHE_RDUNLOCK(cache); - return NULL; - } - - array_init(info); - add_assoc_long(info, "num_slots", cache->num_slots); - add_assoc_long(info, "ttl", cache->ttl); - - add_assoc_double(info, "num_hits", (double)cache->header->num_hits); - add_assoc_double(info, "num_misses", (double)cache->header->num_misses); - add_assoc_double(info, "num_inserts", (double)cache->header->num_inserts); - add_assoc_double(info, "expunges", (double)cache->header->expunges); - - add_assoc_long(info, "start_time", cache->header->start_time); - add_assoc_double(info, "mem_size", (double)cache->header->mem_size); - add_assoc_long(info, "num_entries", cache->header->num_entries); -#ifdef MULTIPART_EVENT_FORMDATA - add_assoc_long(info, "file_upload_progress", 1); -#else - add_assoc_long(info, "file_upload_progress", 0); -#endif -#if APC_MMAP - add_assoc_stringl(info, "memory_type", "mmap", sizeof("mmap")-1, 1); -#else - add_assoc_stringl(info, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1); -#endif - add_assoc_stringl(info, "locking_type", APC_LOCK_TYPE, sizeof(APC_LOCK_TYPE)-1, 1); - - if(!limited) { - /* For each hashtable slot */ - ALLOC_INIT_ZVAL(list); - array_init(list); - - ALLOC_INIT_ZVAL(slots); - array_init(slots); - for (i = 0; i < cache->num_slots; i++) { - p = cache->slots[i]; - j = 0; - for (; p != NULL; p = p->next) { - zval *link = apc_cache_link_info(cache, p TSRMLS_CC); - add_next_index_zval(list, link); - j++; - } - add_next_index_long(slots, j); - } - - /* For each slot pending deletion */ - ALLOC_INIT_ZVAL(deleted_list); - array_init(deleted_list); - - for (p = cache->header->deleted_list; p != NULL; p = p->next) { - zval *link = apc_cache_link_info(cache, p TSRMLS_CC); - add_next_index_zval(deleted_list, link); - } - - add_assoc_zval(info, "cache_list", list); - add_assoc_zval(info, "deleted_list", deleted_list); - add_assoc_zval(info, "slot_distribution", slots); - } - - CACHE_RDUNLOCK(cache); - return info; -} -/* }}} */ - -/* {{{ apc_cache_unlock */ -void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC) -{ - CACHE_UNLOCK(cache); -} -/* }}} */ - -/* {{{ apc_cache_busy */ -zend_bool apc_cache_busy(apc_cache_t* cache) -{ - return cache->header->busy; -} -/* }}} */ - -/* {{{ apc_cache_is_last_key */ -zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t TSRMLS_DC) -{ - apc_keyid_t *lastkey = &cache->header->lastkey; - unsigned int keylen = key->data.user.identifier_len; -#ifdef ZTS - THREAD_T tid = tsrm_thread_id(); - #define FROM_DIFFERENT_THREAD(k) (memcmp(&((k)->tid), &tid, sizeof(THREAD_T))!=0) -#else - pid_t pid = getpid(); - #define FROM_DIFFERENT_THREAD(k) (pid != (k)->pid) -#endif - - - /* unlocked reads, but we're not shooting for 100% success with this */ - if(lastkey->h == key->h && keylen == lastkey->keylen) { - if(lastkey->mtime == t && FROM_DIFFERENT_THREAD(lastkey)) { - /* potential cache slam */ - if(APCG(slam_defense)) { - apc_debug("Potential cache slam averted for key '%s'" TSRMLS_CC, key->data.user.identifier); - return 1; - } - } - } - - return 0; -} -/* }}} */ - -#if NONBLOCKING_LOCK_AVAILABLE -/* {{{ apc_cache_write_lock */ -zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC) -{ - return apc_lck_nb_lock(cache->header->wrlock); -} -/* }}} */ - -/* {{{ apc_cache_write_unlock */ -void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC) -{ - apc_lck_unlock(cache->header->wrlock); -} -/* }}} */ -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker - * vim<600: expandtab sw=4 ts=4 sts=4 - */ | ||
[+] | Deleted | APC-3.1.8.tar.bz2/APC-3.1.8/apc_main.c ^ |
@@ -1,1028 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | APC | - +----------------------------------------------------------------------+ - | Copyright (c) 2006-2011 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 <dcowgill@communityconnect.com> | - | Rasmus Lerdorf <rasmus@php.net> | - | Arun C. Murthy <arunc@yahoo-inc.com> | - | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> | - +----------------------------------------------------------------------+ - - 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: apc_main.c 309002 2011-03-07 19:50:18Z pajoye $ */ - -#include "apc_php.h" -#include "apc_main.h" -#include "apc.h" -#include "apc_lock.h" -#include "apc_cache.h" -#include "apc_compile.h" -#include "apc_globals.h" -#include "apc_sma.h" -#include "apc_stack.h" -#include "apc_zend.h" -#include "apc_pool.h" -#include "apc_string.h" -#include "SAPI.h" -#include "php_scandir.h" -#include "ext/standard/php_var.h" -#include "ext/standard/md5.h" - -#define APC_MAX_SERIALIZERS 16 - -/* {{{ module variables */ - -/* pointer to the original Zend engine compile_file function */ -typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC); -static zend_compile_t *old_compile_file; -static apc_serializer_t apc_serializers[APC_MAX_SERIALIZERS] = {{0,}}; - -/* }}} */ - -/* {{{ get/set old_compile_file (to interact with other extensions that need the compile hook) */ -static zend_compile_t* set_compile_hook(zend_compile_t *ptr) -{ - zend_compile_t *retval = old_compile_file; - - if (ptr != NULL) old_compile_file = ptr; - return retval; -} -/* }}} */ - -/* {{{ install_function */ -static int install_function(apc_function_t fn, apc_context_t* ctxt, int lazy TSRMLS_DC) -{ - int status; - -#if APC_HAVE_LOOKUP_HOOKS - if(lazy && fn.name[0] != '\0' && strncmp(fn.name, "__autoload", fn.name_len) != 0) { - status = zend_hash_add(APCG(lazy_function_table), - fn.name, - fn.name_len+1, - &fn, - sizeof(apc_function_t), - NULL); -#else - if(0) { -#endif - } else { - zend_function *func = apc_copy_function_for_execution(fn.function, ctxt TSRMLS_CC); - status = zend_hash_add(EG(function_table), - fn.name, - fn.name_len+1, - func, - sizeof(fn.function[0]), - NULL); - efree(func); - } - - if (status == FAILURE) { - /* apc_error("Cannot redeclare %s()" TSRMLS_CC, fn.name); */ - } - - return status; -} -/* }}} */ - -/* {{{ apc_lookup_function_hook */ -int apc_lookup_function_hook(char *name, int len, ulong hash, zend_function **fe) { - apc_function_t *fn; - int status = FAILURE; - apc_context_t ctxt = {0,}; - TSRMLS_FETCH(); - - ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC); - ctxt.copy = APC_COPY_OUT_OPCODE; - - if(zend_hash_quick_find(APCG(lazy_function_table), name, len, hash, (void**)&fn) == SUCCESS) { - *fe = apc_copy_function_for_execution(fn->function, &ctxt TSRMLS_CC); - status = zend_hash_add(EG(function_table), - fn->name, - fn->name_len+1, - *fe, - sizeof(zend_function), - NULL); - } - - return status; -} -/* }}} */ - -/* {{{ install_class */ -static int install_class(apc_class_t cl, apc_context_t* ctxt, int lazy TSRMLS_DC) -{ - zend_class_entry* class_entry = cl.class_entry; - zend_class_entry* parent = NULL; - int status; - zend_class_entry** allocated_ce = NULL; - - /* Special case for mangled names. Mangled names are unique to a file. - * There is no way two classes with the same mangled name will occur, - * unless a file is included twice. And if in case, a file is included - * twice, all mangled name conflicts can be ignored and the class redeclaration - * error may be deferred till runtime of the corresponding DECLARE_CLASS - * calls. - */ - - if(cl.name_len != 0 && cl.name[0] == '\0') { - if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) { - return SUCCESS; - } - } - - if(lazy && cl.name_len != 0 && cl.name[0] != '\0') { - status = zend_hash_add(APCG(lazy_class_table), - cl.name, - cl.name_len+1, - &cl, - sizeof(apc_class_t), - NULL); - if(status == FAILURE) { - zend_error(E_ERROR, "Cannot redeclare class %s", cl.name); - } - return status; - } - - /* - * XXX: We need to free this somewhere... - */ - allocated_ce = apc_php_malloc(sizeof(zend_class_entry*) TSRMLS_CC); - - if(!allocated_ce) { - return FAILURE; - } - - *allocated_ce = - class_entry = - apc_copy_class_entry_for_execution(cl.class_entry, ctxt TSRMLS_CC); - - - /* restore parent class pointer for compile-time inheritance */ - if (cl.parent_name != NULL) { - zend_class_entry** parent_ptr = NULL; - /* - * __autoload brings in the old issues with mixed inheritance. - * When a statically inherited class triggers autoload, it runs - * afoul of a potential require_once "parent.php" in the previous - * line, which when executed provides the parent class, but right - * now goes and hits __autoload which could fail. - * - * missing parent == re-compile. - * - * whether __autoload is enabled or not, because __autoload errors - * cause php to die. - * - * Aside: Do NOT pass *strlen(cl.parent_name)+1* because - * zend_lookup_class_ex does it internally anyway! - */ - status = zend_lookup_class_ex(cl.parent_name, - strlen(cl.parent_name), -#ifdef ZEND_ENGINE_2_4 - NULL, -#endif - 0, - &parent_ptr TSRMLS_CC); - if (status == FAILURE) { - if(APCG(report_autofilter)) { - apc_warning("Dynamic inheritance detected for class %s" TSRMLS_CC, cl.name); - } - class_entry->parent = NULL; - return status; - } - else { - parent = *parent_ptr; - class_entry->parent = parent; - zend_do_inheritance(class_entry, parent TSRMLS_CC); - } - - - } - - status = zend_hash_add(EG(class_table), - cl.name, - cl.name_len+1, - allocated_ce, - sizeof(zend_class_entry*), - NULL); - - if (status == FAILURE) { - apc_error("Cannot redeclare class %s" TSRMLS_CC, cl.name); - } - return status; -} -/* }}} */ - -/* {{{ apc_lookup_class_hook */ -int apc_lookup_class_hook(char *name, int len, ulong hash, zend_class_entry ***ce) { - - apc_class_t *cl; - apc_context_t ctxt = {0,}; - TSRMLS_FETCH(); - - if(zend_is_compiling(TSRMLS_C)) { return FAILURE; } - - if(zend_hash_quick_find(APCG(lazy_class_table), name, len, hash, (void**)&cl) == FAILURE) { - return FAILURE; - } - - ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC); - ctxt.copy = APC_COPY_OUT_OPCODE; - - if(install_class(*cl, &ctxt, 0 TSRMLS_CC) == FAILURE) { - apc_warning("apc_lookup_class_hook: could not install %s" TSRMLS_CC, name); - return FAILURE; - } - - if(zend_hash_quick_find(EG(class_table), name, len, hash, (void**)ce) == FAILURE) { - apc_warning("apc_lookup_class_hook: known error trying to fetch class %s" TSRMLS_CC, name); - return FAILURE; - } - - return SUCCESS; - -} -/* }}} */ - -/* {{{ uninstall_class */ -static int uninstall_class(apc_class_t cl TSRMLS_DC) -{ - int status; - - status = zend_hash_del(EG(class_table), - cl.name, - cl.name_len+1); - if (status == FAILURE) { - apc_error("Cannot delete class %s" TSRMLS_CC, cl.name); - } - return status; -} -/* }}} */ - -/* {{{ copy_function_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */ -static int copy_function_name(apc_function_t *pf TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) -{ - zval *internal_ar = va_arg(args, zval *), - *user_ar = va_arg(args, zval *); - zend_function *func = pf->function; - - if (hash_key->nKeyLength == 0 || hash_key->arKey[0] == 0) { - return 0; - } - - if (func->type == ZEND_INTERNAL_FUNCTION) { - add_next_index_stringl(internal_ar, hash_key->arKey, hash_key->nKeyLength-1, 1); - } else if (func->type == ZEND_USER_FUNCTION) { - add_next_index_stringl(user_ar, hash_key->arKey, hash_key->nKeyLength-1, 1); - } - - return 0; -} - -/* {{{ copy_class_or_interface_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */ -static int copy_class_or_interface_name(apc_class_t *cl TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) -{ - zval *array = va_arg(args, zval *); - zend_uint mask = va_arg(args, zend_uint); - zend_uint comply = va_arg(args, zend_uint); - zend_uint comply_mask = (comply)? mask:0; - zend_class_entry *ce = cl->class_entry; - - if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0) - && (comply_mask == (ce->ce_flags & mask))) { - add_next_index_stringl(array, ce->name, ce->name_length, 1); - } - return ZEND_HASH_APPLY_KEEP; -} -/* }}} */ - -/* }}} */ - -/* {{{ apc_defined_function_hook */ -int apc_defined_function_hook(zval *internal, zval *user) { - TSRMLS_FETCH(); - zend_hash_apply_with_arguments(APCG(lazy_function_table) -#ifdef ZEND_ENGINE_2_3 - TSRMLS_CC -#endif - ,(apply_func_args_t) copy_function_name, 2, internal, user); - return 1; -} -/* }}} */ - -/* {{{ apc_declared_class_hook */ -int apc_declared_class_hook(zval *classes, zend_uint mask, zend_uint comply) { - TSRMLS_FETCH(); - zend_hash_apply_with_arguments(APCG(lazy_class_table) -#ifdef ZEND_ENGINE_2_3 - TSRMLS_CC -#endif - , (apply_func_args_t) copy_class_or_interface_name, 3, classes, mask, comply); - return 1; -} -/* }}} */ - -/* {{{ cached_compile */ -static zend_op_array* cached_compile(zend_file_handle* h, - int type, - apc_context_t* ctxt TSRMLS_DC) -{ - apc_cache_entry_t* cache_entry; - int i, ii; - - cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack)); - assert(cache_entry != NULL); - - if (cache_entry->data.file.classes) { - int lazy_classes = APCG(lazy_classes); - for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { - if(install_class(cache_entry->data.file.classes[i], ctxt, lazy_classes TSRMLS_CC) == FAILURE) { - goto default_compile; - } - } - } - - if (cache_entry->data.file.functions) { - int lazy_functions = APCG(lazy_functions); - for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) { - install_function(cache_entry->data.file.functions[i], ctxt, lazy_functions TSRMLS_CC); - } - } - - apc_do_halt_compiler_register(cache_entry->data.file.filename, cache_entry->data.file.halt_offset TSRMLS_CC); - - - return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array, ctxt TSRMLS_CC); - -default_compile: - - if(cache_entry->data.file.classes) { - for(ii = 0; ii < i ; ii++) { - uninstall_class(cache_entry->data.file.classes[ii] TSRMLS_CC); - } - } - - apc_stack_pop(APCG(cache_stack)); /* pop out cache_entry */ - - apc_cache_release(apc_cache, cache_entry TSRMLS_CC); - - /* cannot free up cache data yet, it maybe in use */ - - return NULL; -} -/* }}} */ - -/* {{{ apc_compile_cache_entry */ -zend_bool apc_compile_cache_entry(apc_cache_key_t key, zend_file_handle* h, int type, time_t t, zend_op_array** op_array, apc_cache_entry_t** cache_entry TSRMLS_DC) { - int num_functions, num_classes; - apc_function_t* alloc_functions; - zend_op_array* alloc_op_array; - apc_class_t* alloc_classes; - char *path; - apc_context_t ctxt; - - /* remember how many functions and classes existed before compilation */ - num_functions = zend_hash_num_elements(CG(function_table)); - num_classes = zend_hash_num_elements(CG(class_table)); - - /* compile the file using the default compile function, * - * we set *op_array here so we return opcodes during * - * a failure. We should not return prior to this line. */ - *op_array = old_compile_file(h, type TSRMLS_CC); - if (*op_array == NULL) { - return FAILURE; - } - - ctxt.pool = apc_pool_create(APC_MEDIUM_POOL, apc_sma_malloc, apc_sma_free, - apc_sma_protect, apc_sma_unprotect TSRMLS_CC); - if (!ctxt.pool) { - apc_warning("Unable to allocate memory for pool." TSRMLS_CC); - return FAILURE; - } - ctxt.copy = APC_COPY_IN_OPCODE; - - if(APCG(file_md5)) { - int n; - unsigned char buf[1024]; - PHP_MD5_CTX context; - php_stream *stream; - char *filename; - - if(h->opened_path) { - filename = h->opened_path; - } else { - filename = h->filename; - } - stream = php_stream_open_wrapper(filename, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL); - if(stream) { - PHP_MD5Init(&context); - while((n = php_stream_read(stream, (char*)buf, sizeof(buf))) > 0) { - PHP_MD5Update(&context, buf, n); - } - PHP_MD5Final(key.md5, &context); - php_stream_close(stream); - if(n<0) { - apc_warning("Error while reading '%s' for md5 generation." TSRMLS_CC, filename); - } - } else { - apc_warning("Unable to open '%s' for md5 generation." TSRMLS_CC, filename); - } - } - - if(!(alloc_op_array = apc_copy_op_array(NULL, *op_array, &ctxt TSRMLS_CC))) { - goto freepool; - } - - if(!(alloc_functions = apc_copy_new_functions(num_functions, &ctxt TSRMLS_CC))) { - goto freepool; - } - if(!(alloc_classes = apc_copy_new_classes(*op_array, num_classes, &ctxt TSRMLS_CC))) { - goto freepool; - } - - path = h->opened_path; - if(!path && key.type == APC_CACHE_KEY_FPFILE) path = (char*)key.data.fpfile.fullpath; - if(!path) path=h->filename; - - apc_debug("2. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename); - - if(!(*cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes, &ctxt TSRMLS_CC))) { - goto freepool; - } - - return SUCCESS; - -freepool: - apc_pool_destroy(ctxt.pool TSRMLS_CC); - ctxt.pool = NULL; - - return FAILURE; - -} -/* }}} */ - -/* {{{ my_compile_file - Overrides zend_compile_file */ -static zend_op_array* my_compile_file(zend_file_handle* h, - int type TSRMLS_DC) -{ - apc_cache_key_t key; - apc_cache_entry_t* cache_entry; - zend_op_array* op_array = NULL; - time_t t; - apc_context_t ctxt = {0,}; - int bailout=0; - const char* filename = NULL; - - if (!APCG(enabled) || apc_cache_busy(apc_cache)) { - return old_compile_file(h, type TSRMLS_CC); - } - - if(h->opened_path) { - filename = h->opened_path; - } else { - filename = h->filename; - } - - /* check our regular expression filters */ - if (APCG(filters) && APCG(compiled_filters) && filename) { - int ret = apc_regex_match_array(APCG(compiled_filters), filename); - - if(ret == APC_NEGATIVE_MATCH || (ret != APC_POSITIVE_MATCH && !APCG(cache_by_default))) { - return old_compile_file(h, type TSRMLS_CC); - } - } else if(!APCG(cache_by_default)) { - return old_compile_file(h, type TSRMLS_CC); - } - APCG(current_cache) = apc_cache; - - - t = apc_time(); - - apc_debug("1. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename); - - /* try to create a cache key; if we fail, give up on caching */ - if (!apc_cache_make_file_key(&key, h->filename, PG(include_path), t TSRMLS_CC)) { - return old_compile_file(h, type TSRMLS_CC); - } - - if(!APCG(force_file_update)) { - /* search for the file in the cache */ - cache_entry = apc_cache_find(apc_cache, key, t TSRMLS_CC); - ctxt.force_update = 0; - } else { - cache_entry = NULL; - ctxt.force_update = 1; - } - - if (cache_entry != NULL) { - int dummy = 1; - - ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, - apc_sma_protect, apc_sma_unprotect TSRMLS_CC); - if (!ctxt.pool) { - apc_warning("Unable to allocate memory for pool." TSRMLS_CC); - return old_compile_file(h, type TSRMLS_CC); - } - ctxt.copy = APC_COPY_OUT_OPCODE; - - zend_hash_add(&EG(included_files), cache_entry->data.file.filename, - strlen(cache_entry->data.file.filename)+1, - (void *)&dummy, sizeof(int), NULL); - - apc_stack_push(APCG(cache_stack), cache_entry TSRMLS_CC); - op_array = cached_compile(h, type, &ctxt TSRMLS_CC); - - if(op_array) { -#ifdef APC_FILEHITS - /* If the file comes from the cache, add it to the global request file list */ - add_next_index_string(APCG(filehits), h->filename, 1); -#endif - /* this is an unpool, which has no cleanup - this only free's the pool header */ - apc_pool_destroy(ctxt.pool TSRMLS_CC); - - /* We might leak fds without this hack */ - if (h->type != ZEND_HANDLE_FILENAME) { - zend_llist_add_element(&CG(open_files), h); - } - - op_array->filename = filename; - return op_array; - } - if(APCG(report_autofilter)) { - apc_warning("Autofiltering %s" TSRMLS_CC, - (h->opened_path ? h->opened_path : h->filename)); - apc_warning("Recompiling %s" TSRMLS_CC, cache_entry->data.file.filename); - } - /* TODO: check what happens with EG(included_files) */ - } - - /* Make sure the mtime reflects the files last known mtime, and we respect max_file_size in the case of fpstat==0 */ - if(key.type == APC_CACHE_KEY_FPFILE) { - apc_fileinfo_t fileinfo; - struct stat *tmp_buf = NULL; - if(!strcmp(SG(request_info).path_translated, h->filename)) { - tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */ - } - if(tmp_buf) { - fileinfo.st_buf.sb = *tmp_buf; - } else { - if (apc_search_paths(h->filename, PG(include_path), &fileinfo TSRMLS_CC) != 0) { - apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC,h->filename,SG(request_info).path_translated); - return old_compile_file(h, type TSRMLS_CC); - } - } - if (APCG(max_file_size) < fileinfo.st_buf.sb.st_size) { - apc_debug("File is too big %s (%ld) - bailing\n" TSRMLS_CC, h->filename, fileinfo.st_buf.sb.st_size); - return old_compile_file(h, type TSRMLS_CC); - } - key.mtime = fileinfo.st_buf.sb.st_mtime; - } - - HANDLE_BLOCK_INTERRUPTIONS(); - -#if NONBLOCKING_LOCK_AVAILABLE - if(APCG(write_lock)) { - if(!apc_cache_write_lock(apc_cache TSRMLS_CC)) { - HANDLE_UNBLOCK_INTERRUPTIONS(); - return old_compile_file(h, type TSRMLS_CC); - } - } -#endif - - zend_try { - if (apc_compile_cache_entry(key, h, type, t, &op_array, &cache_entry TSRMLS_CC) == SUCCESS) { - ctxt.pool = cache_entry->pool; - ctxt.copy = APC_COPY_IN_OPCODE; - if (apc_cache_insert(apc_cache, key, cache_entry, &ctxt, t TSRMLS_CC) != 1) { - apc_pool_destroy(ctxt.pool TSRMLS_CC); - ctxt.pool = NULL; - } - } - } zend_catch { - bailout=1; /* in the event of a bailout, ensure we don't create a dead-lock */ - } zend_end_try(); - - APCG(current_cache) = NULL; - -#if NONBLOCKING_LOCK_AVAILABLE - if(APCG(write_lock)) { - apc_cache_write_unlock(apc_cache TSRMLS_CC); - } -#endif - HANDLE_UNBLOCK_INTERRUPTIONS(); - - if (bailout) zend_bailout(); - - return op_array; -} -/* }}} */ - -/* {{{ data preload */ - -extern int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC); - -static zval* data_unserialize(const char *filename TSRMLS_DC) -{ - zval* retval; - long len = 0; - struct stat sb; - char *contents, *tmp; - FILE *fp; - php_unserialize_data_t var_hash; - - if(VCWD_STAT(filename, &sb) == -1) { - return NULL; - } - - fp = fopen(filename, "rb"); - - len = sizeof(char)*sb.st_size; - - tmp = contents = malloc(len); - - if(!contents) { - return NULL; - } - - if(fread(contents, 1, len, fp) < 1) { - free(contents); - return NULL; - } - - MAKE_STD_ZVAL(retval); - - PHP_VAR_UNSERIALIZE_INIT(var_hash); - - /* I wish I could use json */ - if(!php_var_unserialize(&retval, (const unsigned char**)&tmp, (const unsigned char*)(contents+len), &var_hash TSRMLS_CC)) { - zval_ptr_dtor(&retval); - return NULL; - } - - PHP_VAR_UNSERIALIZE_DESTROY(var_hash); - - free(contents); - fclose(fp); - - return retval; -} - -static int apc_load_data(const char *data_file TSRMLS_DC) -{ - char *p; - char key[MAXPATHLEN] = {0,}; - unsigned int key_len; - zval *data; - - p = strrchr(data_file, DEFAULT_SLASH); - - if(p && p[1]) { - strlcpy(key, p+1, sizeof(key)); - p = strrchr(key, '.'); - - if(p) { - p[0] = '\0'; - key_len = strlen(key); - - data = data_unserialize(data_file TSRMLS_CC); - if(data) { - _apc_store(key, key_len, data, 0, 1 TSRMLS_CC); - } - return 1; - } - } - - return 0; -} - -static int apc_walk_dir(const char *path TSRMLS_DC) -{ - char file[MAXPATHLEN]={0,}; - int ndir, i; - char *p = NULL; - struct dirent **namelist = NULL; - - if ((ndir = php_scandir(path, &namelist, 0, php_alphasort)) > 0) - { - for (i = 0; i < ndir; i++) - { - /* check for extension */ - if (!(p = strrchr(namelist[i]->d_name, '.')) - || (p && strcmp(p, ".data"))) - { - free(namelist[i]); - continue; - } - snprintf(file, MAXPATHLEN, "%s%c%s", - path, DEFAULT_SLASH, namelist[i]->d_name); - if(!apc_load_data(file TSRMLS_CC)) - { - /* print error */ - } - free(namelist[i]); - } - free(namelist); - } - - return 1; -} - -void apc_data_preload(TSRMLS_D) -{ - if(!APCG(preload_path)) return; - - apc_walk_dir(APCG(preload_path) TSRMLS_CC); -} -/* }}} */ - -/* {{{ apc_serializer hooks */ -static int _apc_register_serializer(const char* name, apc_serialize_t serialize, - apc_unserialize_t unserialize, - void *config TSRMLS_DC) -{ - int i; - apc_serializer_t *serializer; - - for(i = 0; i < APC_MAX_SERIALIZERS; i++) { - serializer = &apc_serializers[i]; - if(!serializer->name) { - /* empty entry */ - serializer->name = name; /* assumed to be const */ - serializer->serialize = serialize; - serializer->unserialize = unserialize; - serializer->config = config; - apc_serializers[i+1].name = NULL; - return 1; - } - } - - return 0; -} - -apc_serializer_t* apc_find_serializer(const char* name TSRMLS_DC) -{ - int i; - apc_serializer_t *serializer; - - for(i = 0; i < APC_MAX_SERIALIZERS; i++) { - serializer = &apc_serializers[i]; - if(serializer->name && (strcmp(serializer->name, name) == 0)) { - return serializer; - } - } - return NULL; -} - -apc_serializer_t* apc_get_serializers(TSRMLS_D) -{ - return &(apc_serializers[0]); -} -/* }}} */ - -/* {{{ module init and shutdown */ - -int apc_module_init(int module_number TSRMLS_DC) -{ - /* apc initialization */ -#if APC_MMAP - apc_sma_init(APCG(shm_segments), APCG(shm_size), APCG(mmap_file_mask) TSRMLS_CC); -#else - apc_sma_init(APCG(shm_segments), APCG(shm_size), NULL TSRMLS_CC); -#endif - apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl) TSRMLS_CC); - apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl) TSRMLS_CC); - - /* override compilation */ - old_compile_file = zend_compile_file; - zend_compile_file = my_compile_file; - REGISTER_LONG_CONSTANT("\000apc_magic", (long)&set_compile_hook, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("\000apc_compile_file", (long)&my_compile_file, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT(APC_SERIALIZER_CONSTANT, (long)&_apc_register_serializer, CONST_PERSISTENT | CONST_CS); - - /* test out the constant function pointer */ - apc_register_serializer("php", APC_SERIALIZER_NAME(php), APC_UNSERIALIZER_NAME(php), NULL TSRMLS_CC); - - assert(apc_serializers[0].name != NULL); - - apc_pool_init(); - - apc_data_preload(TSRMLS_C); - -#if APC_HAVE_LOOKUP_HOOKS - if(APCG(lazy_functions)) { - zend_set_lookup_function_hook(apc_lookup_function_hook TSRMLS_CC); - zend_set_defined_function_hook(apc_defined_function_hook TSRMLS_CC); - } - if(APCG(lazy_classes)) { - zend_set_lookup_class_hook(apc_lookup_class_hook TSRMLS_CC); - zend_set_declared_class_hook(apc_declared_class_hook TSRMLS_CC); - } -#else - if(APCG(lazy_functions) || APCG(lazy_classes)) { - apc_warning("Lazy function/class loading not available with this version of PHP, please disable APC lazy loading." TSRMLS_CC); - APCG(lazy_functions) = APCG(lazy_classes) = 0; - } -#endif - -#ifdef ZEND_ENGINE_2_4 - apc_interned_strings_init(TSRMLS_C); -#endif - - APCG(initialized) = 1; - return 0; -} - -int apc_module_shutdown(TSRMLS_D) -{ - if (!APCG(initialized)) - return 0; - - /* restore compilation */ - zend_compile_file = old_compile_file; - - /* - * In case we got interrupted by a SIGTERM or something else during execution - * we may have cache entries left on the stack that we need to check to make - * sure that any functions or classes these may have added to the global function - * and class tables are removed before we blow away the memory that hold them. - * - * This is merely to remove memory leak warnings - as the process is terminated - * immediately after shutdown. The following while loop can be removed without - * affecting anything else. - */ - while (apc_stack_size(APCG(cache_stack)) > 0) { - int i; - apc_cache_entry_t* cache_entry = (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack)); - if (cache_entry->data.file.functions) { - for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) { - zend_hash_del(EG(function_table), - cache_entry->data.file.functions[i].name, - cache_entry->data.file.functions[i].name_len+1); - } - } - if (cache_entry->data.file.classes) { - for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { - zend_hash_del(EG(class_table), - cache_entry->data.file.classes[i].name, - cache_entry->data.file.classes[i].name_len+1); - } - } - apc_cache_release(apc_cache, cache_entry TSRMLS_CC); - } - - apc_cache_destroy(apc_cache TSRMLS_CC); - apc_cache_destroy(apc_user_cache TSRMLS_CC); - apc_sma_cleanup(TSRMLS_C); - -#ifdef ZEND_ENGINE_2_4 - apc_interned_strings_shutdown(TSRMLS_C); -#endif - - APCG(initialized) = 0; - return 0; -} - -/* }}} */ - -/* {{{ process init and shutdown */ -int apc_process_init(int module_number TSRMLS_DC) -{ - return 0; -} - -int apc_process_shutdown(TSRMLS_D) -{ - return 0; -} -/* }}} */ - - -/* {{{ apc_deactivate */ -static void apc_deactivate(TSRMLS_D) -{ - /* The execution stack was unwound, which prevented us from decrementing - * the reference counts on active cache entries in `my_execute`. - */ - while (apc_stack_size(APCG(cache_stack)) > 0) { - int i; - zend_class_entry* zce = NULL; - void ** centry = (void*)(&zce); - zend_class_entry** pzce = NULL; - - apc_cache_entry_t* cache_entry = - (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack)); - - if (cache_entry->data.file.classes) { - for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { - centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */ - if(zend_hash_find(EG(class_table), - cache_entry->data.file.classes[i].name, - cache_entry->data.file.classes[i].name_len+1, - (void**)centry) == FAILURE) - { - /* double inclusion of conditional classes ends up failing - * this lookup the second time around. - */ - continue; - } - - zce = *pzce; - - zend_hash_del(EG(class_table), - cache_entry->data.file.classes[i].name, - cache_entry->data.file.classes[i].name_len+1); - - apc_free_class_entry_after_execution(zce TSRMLS_CC); - } - } - apc_cache_release(apc_cache, cache_entry TSRMLS_CC); - } -} -/* }}} */ - -/* {{{ request init and shutdown */ - -int apc_request_init(TSRMLS_D) -{ - apc_stack_clear(APCG(cache_stack)); - if (!APCG(compiled_filters) && APCG(filters)) { - /* compile regex filters here to avoid race condition between MINIT of PCRE and APC. - * This should be moved to apc_cache_create() if this race condition between modules is resolved */ - APCG(compiled_filters) = apc_regex_compile_array(APCG(filters) TSRMLS_CC); - } - - if (!APCG(serializer) && APCG(serializer_name)) { - /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */ - APCG(serializer) = apc_find_serializer(APCG(serializer_name) TSRMLS_CC); - } - -#if APC_HAVE_LOOKUP_HOOKS - if(APCG(lazy_functions)) { - APCG(lazy_function_table) = emalloc(sizeof(HashTable)); - zend_hash_init(APCG(lazy_function_table), 0, NULL, NULL, 0); - } - if(APCG(lazy_classes)) { - APCG(lazy_class_table) = emalloc(sizeof(HashTable)); - zend_hash_init(APCG(lazy_class_table), 0, NULL, NULL, 0); - } -#endif - -#ifdef APC_FILEHITS - ALLOC_INIT_ZVAL(APCG(filehits)); - array_init(APCG(filehits)); -#endif - - return 0; -} - -int apc_request_shutdown(TSRMLS_D) -{ -#if APC_HAVE_LOOKUP_HOOKS - if(APCG(lazy_class_table)) { - zend_hash_destroy(APCG(lazy_class_table)); - efree(APCG(lazy_class_table)); - } - if(APCG(lazy_function_table)) { - zend_hash_destroy(APCG(lazy_function_table)); - efree(APCG(lazy_function_table)); - } -#endif - - apc_deactivate(TSRMLS_C); - -#ifdef APC_FILEHITS - zval_ptr_dtor(&APCG(filehits)); -#endif - return 0; -} - -/* }}} */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker - * vim<600: expandtab sw=4 ts=4 sts=4 - */ | ||
[+] | Deleted | APC-3.1.8.tar.bz2/APC-3.1.8/php_apc.h ^ |
@@ -1,54 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | APC | - +----------------------------------------------------------------------+ - | Copyright (c) 2006-2011 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 <dcowgill@communityconnect.com> | - | George Schlossnagle <george@omniti.com> | - | Rasmus Lerdorf <rasmus@php.net> | - +----------------------------------------------------------------------+ - - 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.h 309979 2011-04-06 09:50:32Z pajoye $ */ - -#ifndef PHP_APC_H -#define PHP_APC_H - -#include "apc_php.h" -#include "apc_globals.h" - -#define PHP_APC_VERSION "3.1.8" - -extern zend_module_entry apc_module_entry; -#define apc_module_ptr &apc_module_entry - -#define phpext_apc_ptr apc_module_ptr - -#endif /* PHP_APC_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker - * vim<600: expandtab sw=4 ts=4 sts=4 - */ | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/CHANGELOG ^ |
(renamed from APC-3.1.8/CHANGELOG) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/CHANGELOG ^ |
(renamed from APC-3.1.8/CHANGELOG) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/INSTALL ^ |
(renamed from APC-3.1.8/INSTALL) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/INSTALL ^ |
(renamed from APC-3.1.8/INSTALL) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/LICENSE ^ |
(renamed from APC-3.1.8/LICENSE) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/LICENSE ^ |
(renamed from APC-3.1.8/LICENSE) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/NOTICE ^ |
(renamed from APC-3.1.8/NOTICE) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/NOTICE ^ |
(renamed from APC-3.1.8/NOTICE) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/TECHNOTES.txt ^ |
(renamed from APC-3.1.8/TECHNOTES.txt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/TECHNOTES.txt ^ |
(renamed from APC-3.1.8/TECHNOTES.txt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/TODO ^ |
(renamed from APC-3.1.8/TODO) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/TODO ^ |
(renamed from APC-3.1.8/TODO) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc.c ^ |
(renamed from APC-3.1.8/apc.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc.c ^ |
(renamed from APC-3.1.8/apc.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc.h ^ |
(renamed from APC-3.1.8/apc.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc.h ^ |
(renamed from APC-3.1.8/apc.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc.php ^ |
(renamed from APC-3.1.8/apc.php) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc.php ^ |
(renamed from APC-3.1.8/apc.php) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.c ^ |
(renamed from APC-3.1.8/apc_bin.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.c ^ |
(renamed from APC-3.1.8/apc_bin.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.h ^ |
(renamed from APC-3.1.8/apc_bin.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_bin.h ^ |
(renamed from APC-3.1.8/apc_bin.h) | ||
[+] | Added | APC-3.1.9.tar.bz2/APC-3.1.9/apc_cache.c ^ |
@@ -0,0 +1,1381 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2011 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 <dcowgill@communityconnect.com> | + | Rasmus Lerdorf <rasmus@php.net> | + | Arun C. Murthy <arunc@yahoo-inc.com> | + | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> | + +----------------------------------------------------------------------+ + + 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: apc_cache.c 309488 2011-03-20 23:59:42Z pajoye $ */ + +#include "apc_cache.h" +#include "apc_zend.h" +#include "apc_sma.h" +#include "apc_globals.h" +#include "SAPI.h" +#include "TSRM.h" +#include "ext/standard/md5.h" + +/* TODO: rehash when load factor exceeds threshold */ + +#define CHECK(p) { if ((p) == NULL) return NULL; } + +/* {{{ key_equals */ +#define key_equals(a, b) (a.inode==b.inode && a.device==b.device) +/* }}} */ + +static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC); + +/* {{{ hash */ +static unsigned long hash(apc_cache_key_t key) +{ + return (unsigned long)(key.data.file.device + key.data.file.inode); +} +/* }}} */ + +/* {{{ string_nhash_8 */ +#define string_nhash_8(s,len) (unsigned long)(zend_inline_hash_func((s), len)) +/* }}} */ + +/* {{{ murmurhash */ +#if 0 +static inline unsigned long murmurhash(const char *skey, size_t keylen) +{ + const long m = 0x7fd652ad; + const long r = 16; + unsigned int h = 0xdeadbeef; + + while(keylen >= 4) + { + h += *(unsigned int*)skey; + h *= m; + h ^= h >> r; + + skey += 4; + keylen -= 4; + } + + switch(keylen) + { + case 3: + h += skey[2] << 16; + case 2: + h += skey[1] << 8; + case 1: + h += skey[0]; + h *= m; + h ^= h >> r; + }; + + h *= m; + h ^= h >> 10; + h *= m; + h ^= h >> 17; + + return h; +} +#endif +/* }}} */ + + +/* {{{ make_prime */ +static int const primes[] = { + 257, /* 256 */ + 521, /* 512 */ + 1031, /* 1024 */ + 2053, /* 2048 */ + 3079, /* 3072 */ + 4099, /* 4096 */ + 5147, /* 5120 */ + 6151, /* 6144 */ + 7177, /* 7168 */ + 8209, /* 8192 */ + 9221, /* 9216 */ +10243, /* 10240 */ +11273, /* 11264 */ +12289, /* 12288 */ +13313, /* 13312 */ +14341, /* 14336 */ +15361, /* 15360 */ +16411, /* 16384 */ +17417, /* 17408 */ +18433, /* 18432 */ +19457, /* 19456 */ +0 /* sentinel */ +}; + +static int make_prime(int n) +{ + int *k = (int*)primes; + while(*k) { + if((*k) > n) return *k; + k++; + } + return *(k-1); +} +/* }}} */ + +/* {{{ make_slot */ +slot_t* make_slot(apc_cache_key_t *key, apc_cache_entry_t* value, slot_t* next, time_t t TSRMLS_DC) +{ + slot_t* p = apc_pool_alloc(value->pool, sizeof(slot_t)); + + if (!p) return NULL; + + if(key->type == APC_CACHE_KEY_USER) { + char *identifier = (char*) apc_pmemcpy(key->data.user.identifier, key->data.user.identifier_len, value->pool TSRMLS_CC); + if (!identifier) { + return NULL; + } + key->data.user.identifier = identifier; + } else if(key->type == APC_CACHE_KEY_FPFILE) { + char *fullpath = (char*) apc_pstrdup(key->data.fpfile.fullpath, value->pool TSRMLS_CC); + if (!fullpath) { + return NULL; + } + key->data.fpfile.fullpath = fullpath; + } + p->key = key[0]; + p->value = value; + p->next = next; + p->num_hits = 0; + p->creation_time = t; + p->access_time = t; + p->deletion_time = 0; + return p; +} +/* }}} */ + +/* {{{ free_slot */ +static void free_slot(slot_t* slot TSRMLS_DC) +{ + apc_pool_destroy(slot->value->pool TSRMLS_CC); +} +/* }}} */ + +/* {{{ remove_slot */ +static void remove_slot(apc_cache_t* cache, slot_t** slot TSRMLS_DC) +{ + slot_t* dead = *slot; + *slot = (*slot)->next; + + cache->header->mem_size -= dead->value->mem_size; + CACHE_FAST_DEC(cache, cache->header->num_entries); + if (dead->value->ref_count <= 0) { + free_slot(dead TSRMLS_CC); + } + else { + dead->next = cache->header->deleted_list; + dead->deletion_time = time(0); + cache->header->deleted_list = dead; + } +} +/* }}} */ + +/* {{{ process_pending_removals */ +static void process_pending_removals(apc_cache_t* cache TSRMLS_DC) +{ + slot_t** slot; + time_t now; + + /* This function scans the list of removed cache entries and deletes any + * entry whose reference count is zero (indicating that it is no longer + * being executed) or that has been on the pending list for more than + * cache->gc_ttl seconds (we issue a warning in the latter case). + */ + + if (!cache->header->deleted_list) + return; + + slot = &cache->header->deleted_list; + now = time(0); + + while (*slot != NULL) { + int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0; + + if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) { + slot_t* dead = *slot; + + if (dead->value->ref_count > 0) { + switch(dead->value->type) { + case APC_CACHE_ENTRY_FILE: + apc_debug("GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds" TSRMLS_CC, + dead->value->data.file.filename, dead->key.data.file.device, dead->key.data.file.inode, gc_sec); + break; + case APC_CACHE_ENTRY_USER: + apc_debug("GC cache entry '%s' was on gc-list for %d seconds" TSRMLS_CC, dead->value->data.user.info, gc_sec); + break; + } + } + *slot = dead->next; + free_slot(dead TSRMLS_CC); + } + else { + slot = &(*slot)->next; + } + } +} +/* }}} */ + +/* {{{ prevent_garbage_collection */ +static void prevent_garbage_collection(apc_cache_entry_t* entry) +{ + /* set reference counts on zend objects to an arbitrarily high value to + * prevent garbage collection after execution */ + + enum { BIG_VALUE = 1000 }; + + if(entry->data.file.op_array) { + entry->data.file.op_array->refcount[0] = BIG_VALUE; + } + if (entry->data.file.functions) { + int i; + apc_function_t* fns = entry->data.file.functions; + for (i=0; fns[i].function != NULL; i++) { + *(fns[i].function->op_array.refcount) = BIG_VALUE; + } + } + if (entry->data.file.classes) { + int i; + apc_class_t* classes = entry->data.file.classes; + for (i=0; classes[i].class_entry != NULL; i++) { + classes[i].class_entry->refcount = BIG_VALUE; + } + } +} +/* }}} */ + +/* {{{ apc_cache_create */ +apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC) +{ + apc_cache_t* cache; + int cache_size; + int num_slots; + + num_slots = make_prime(size_hint > 0 ? size_hint : 2000); + + cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t) TSRMLS_CC); + cache_size = sizeof(cache_header_t) + num_slots*sizeof(slot_t*); + + cache->shmaddr = apc_sma_malloc(cache_size TSRMLS_CC); + if(!cache->shmaddr) { + apc_error("Unable to allocate shared memory for cache structures. (Perhaps your shared memory size isn't large enough?). " TSRMLS_CC); + return NULL; + } + memset(cache->shmaddr, 0, cache_size); + + cache->header = (cache_header_t*) cache->shmaddr; + cache->header->num_hits = 0; + cache->header->num_misses = 0; + cache->header->deleted_list = NULL; + cache->header->start_time = time(NULL); + cache->header->expunges = 0; + cache->header->busy = 0; + + cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(cache_header_t)); + cache->num_slots = num_slots; + cache->gc_ttl = gc_ttl; + cache->ttl = ttl; + CREATE_LOCK(cache->header->lock); +#if NONBLOCKING_LOCK_AVAILABLE + CREATE_LOCK(cache->header->wrlock); +#endif + memset(cache->slots, 0, sizeof(slot_t*)*num_slots); + cache->expunge_cb = apc_cache_expunge; + cache->has_lock = 0; + + return cache; +} +/* }}} */ + +/* {{{ apc_cache_destroy */ +void apc_cache_destroy(apc_cache_t* cache TSRMLS_DC) +{ + DESTROY_LOCK(cache->header->lock); +#ifdef NONBLOCKING_LOCK_AVAILABLE + DESTROY_LOCK(cache->header->wrlock); +#endif + apc_efree(cache TSRMLS_CC); +} +/* }}} */ + +/* {{{ apc_cache_clear */ +void apc_cache_clear(apc_cache_t* cache TSRMLS_DC) +{ + int i; + + if(!cache) return; + + CACHE_LOCK(cache); + cache->header->busy = 1; + cache->header->num_hits = 0; + cache->header->num_misses = 0; + cache->header->start_time = time(NULL); + cache->header->expunges = 0; + + for (i = 0; i < cache->num_slots; i++) { + slot_t* p = cache->slots[i]; + while (p) { + remove_slot(cache, &p TSRMLS_CC); + } + cache->slots[i] = NULL; + } + + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); + + cache->header->busy = 0; + CACHE_UNLOCK(cache); +} +/* }}} */ + +/* {{{ apc_cache_expunge */ +static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC) +{ + int i; + time_t t; + + t = apc_time(); + + if(!cache) return; + + if(!cache->ttl) { + /* + * If cache->ttl is not set, we wipe out the entire cache when + * we run out of space. + */ + CACHE_SAFE_LOCK(cache); + process_pending_removals(cache TSRMLS_CC); + if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) { + /* probably a queued up expunge, we don't need to do this */ + CACHE_SAFE_UNLOCK(cache); + return; + } + cache->header->busy = 1; + CACHE_FAST_INC(cache, cache->header->expunges); +clear_all: + for (i = 0; i < cache->num_slots; i++) { + slot_t* p = cache->slots[i]; + while (p) { + remove_slot(cache, &p TSRMLS_CC); + } + cache->slots[i] = NULL; + } + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); + cache->header->busy = 0; + CACHE_SAFE_UNLOCK(cache); + } else { + slot_t **p; + /* + * If the ttl for the cache is set we walk through and delete stale + * entries. For the user cache that is slightly confusing since + * we have the individual entry ttl's we can look at, but that would be + * too much work. So if you want the user cache expunged, set a high + * default apc.user_ttl and still provide a specific ttl for each entry + * on insert + */ + + CACHE_SAFE_LOCK(cache); + process_pending_removals(cache TSRMLS_CC); + if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) { + /* probably a queued up expunge, we don't need to do this */ + CACHE_SAFE_UNLOCK(cache); + return; + } + cache->header->busy = 1; + CACHE_FAST_INC(cache, cache->header->expunges); + for (i = 0; i < cache->num_slots; i++) { + p = &cache->slots[i]; + while(*p) { + /* + * For the user cache we look at the individual entry ttl values + * and if not set fall back to the default ttl for the user cache + */ + if((*p)->value->type == APC_CACHE_ENTRY_USER) { + if((*p)->value->data.user.ttl) { + if((time_t) ((*p)->creation_time + (*p)->value->data.user.ttl) < t) { + remove_slot(cache, p TSRMLS_CC); + continue; + } + } else if(cache->ttl) { + if((*p)->creation_time + cache->ttl < t) { + remove_slot(cache, p TSRMLS_CC); + continue; + } + } + } else if((*p)->access_time < (t - cache->ttl)) { + remove_slot(cache, p TSRMLS_CC); + continue; + } + p = &(*p)->next; + } + } + + if (!apc_sma_get_avail_size(size)) { + /* TODO: re-do this to remove goto across locked sections */ + goto clear_all; + } + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); + cache->header->busy = 0; + CACHE_SAFE_UNLOCK(cache); + } +} +/* }}} */ + +/* {{{ apc_cache_insert */ +static inline int _apc_cache_insert(apc_cache_t* cache, + apc_cache_key_t key, + apc_cache_entry_t* value, + apc_context_t* ctxt, + time_t t + TSRMLS_DC) +{ + slot_t** slot; + + if (!value) { + return 0; + } + + apc_debug("Inserting [%s]\n" TSRMLS_CC, value->data.file.filename); + + process_pending_removals(cache TSRMLS_CC); + + slot = &cache->slots[key.h % cache->num_slots]; + + while(*slot) { + if(key.type == (*slot)->key.type) { + if(key.type == APC_CACHE_KEY_FILE) { + if(key_equals((*slot)->key.data.file, key.data.file)) { + /* If existing slot for the same device+inode is different, remove it and insert the new version */ + if (ctxt->force_update || (*slot)->key.mtime != key.mtime) { + remove_slot(cache, slot TSRMLS_CC); + break; + } + return 0; + } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { + remove_slot(cache, slot TSRMLS_CC); + continue; + } + } else { /* APC_CACHE_KEY_FPFILE */ + if((key.h == (*slot)->key.h) && + !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { + /* Hrm.. it's already here, remove it and insert new one */ + remove_slot(cache, slot TSRMLS_CC); + break; + } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { + remove_slot(cache, slot TSRMLS_CC); + continue; + } + } + } + slot = &(*slot)->next; + } + + if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) { + return -1; + } + + value->mem_size = ctxt->pool->size; + cache->header->mem_size += ctxt->pool->size; + CACHE_FAST_INC(cache, cache->header->num_entries); + CACHE_FAST_INC(cache, cache->header->num_inserts); + + return 1; +} +/* }}} */ + +/* {{{ apc_cache_insert */ +int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t *ctxt, time_t t TSRMLS_DC) +{ + int rval; + CACHE_LOCK(cache); + rval = _apc_cache_insert(cache, key, value, ctxt, t TSRMLS_CC); + CACHE_UNLOCK(cache); + return rval; +} +/* }}} */ + +/* {{{ apc_cache_insert */ +int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys, apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries TSRMLS_DC) +{ + int *rval; + int i; + + rval = emalloc(sizeof(int) * num_entries); + CACHE_LOCK(cache); + for (i=0; i < num_entries; i++) { + if (values[i]) { + ctxt->pool = values[i]->pool; + rval[i] = _apc_cache_insert(cache, keys[i], values[i], ctxt, t TSRMLS_CC); + } + } + CACHE_UNLOCK(cache); + return rval; +} +/* }}} */ + + +/* {{{ apc_cache_user_insert */ +int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC) +{ + slot_t** slot; + unsigned int keylen = key.data.user.identifier_len; + apc_keyid_t *lastkey = &cache->header->lastkey; + + if (!value) { + return 0; + } + + if(apc_cache_busy(cache)) { + /* cache cleanup in progress, do not wait */ + return 0; + } + + if(apc_cache_is_last_key(cache, &key, t TSRMLS_CC)) { + /* potential cache slam */ + return 0; + } + + CACHE_LOCK(cache); + + memset(lastkey, 0, sizeof(apc_keyid_t)); + + lastkey->h = key.h; + lastkey->keylen = keylen; + lastkey->mtime = t; +#ifdef ZTS + lastkey->tid = tsrm_thread_id(); +#else + lastkey->pid = getpid(); +#endif + + /* we do not reset lastkey after the insert. Whether it is inserted + * or not, another insert in the same second is always a bad idea. + */ + + process_pending_removals(cache TSRMLS_CC); + + slot = &cache->slots[key.h % cache->num_slots]; + + while (*slot) { + if (((*slot)->key.h == key.h) && + (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, keylen))) { + /* + * At this point we have found the user cache entry. If we are doing + * an exclusive insert (apc_add) we are going to bail right away if + * the user entry already exists and it has no ttl, or + * there is a ttl and the entry has not timed out yet. + */ + if(exclusive && ( !(*slot)->value->data.user.ttl || + ( (*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t ) + ) ) { + goto fail; + } + remove_slot(cache, slot TSRMLS_CC); + break; + } else + /* + * This is a bit nasty. The idea here is to do runtime cleanup of the linked list of + * slot entries so we don't always have to skip past a bunch of stale entries. We check + * for staleness here and get rid of them by first checking to see if the cache has a global + * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly + * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl + */ + if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) || + ((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) { + remove_slot(cache, slot TSRMLS_CC); + continue; + } + slot = &(*slot)->next; + } + + if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) { + goto fail; + } + + value->mem_size = ctxt->pool->size; + cache->header->mem_size += ctxt->pool->size; + + CACHE_FAST_INC(cache, cache->header->num_entries); + CACHE_FAST_INC(cache, cache->header->num_inserts); + + CACHE_UNLOCK(cache); + + return 1; + +fail: + CACHE_UNLOCK(cache); + + return 0; +} +/* }}} */ + +/* {{{ apc_cache_find_slot */ +slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC) +{ + slot_t** slot; + volatile slot_t* retval = NULL; + + CACHE_RDLOCK(cache); + if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots]; + else slot = &cache->slots[key.h % cache->num_slots]; + + while (*slot) { + if(key.type == (*slot)->key.type) { + if(key.type == APC_CACHE_KEY_FILE) { + if(key_equals((*slot)->key.data.file, key.data.file)) { + if((*slot)->key.mtime != key.mtime) { + #if (USE_READ_LOCKS == 0) + /* this is merely a memory-friendly optimization, if we do have a write-lock + * might as well move this to the deleted_list right-away. Otherwise an insert + * of the same key wil do it (or an expunge, *eventually*). + */ + remove_slot(cache, slot TSRMLS_CC); + #endif + CACHE_SAFE_INC(cache, cache->header->num_misses); + CACHE_RDUNLOCK(cache); + return NULL; + } + CACHE_SAFE_INC(cache, (*slot)->num_hits); + CACHE_SAFE_INC(cache, (*slot)->value->ref_count); + (*slot)->access_time = t; + prevent_garbage_collection((*slot)->value); + CACHE_FAST_INC(cache, cache->header->num_hits); + retval = *slot; + CACHE_RDUNLOCK(cache); + return (slot_t*)retval; + } + } else { /* APC_CACHE_KEY_FPFILE */ + if(((*slot)->key.h == key.h) && + !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { + /* TTL Check ? */ + CACHE_SAFE_INC(cache, (*slot)->num_hits); + CACHE_SAFE_INC(cache, (*slot)->value->ref_count); + (*slot)->access_time = t; + prevent_garbage_collection((*slot)->value); + CACHE_FAST_INC(cache, cache->header->num_hits); + retval = *slot; + CACHE_RDUNLOCK(cache); + return (slot_t*)retval; + } + } + } + slot = &(*slot)->next; + } + CACHE_FAST_INC(cache, cache->header->num_misses); + CACHE_RDUNLOCK(cache); + return NULL; +} +/* }}} */ + +/* {{{ apc_cache_find */ +apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC) +{ + slot_t * slot = apc_cache_find_slot(cache, key, t TSRMLS_CC); + apc_debug("apc_cache_find [%i]\n" TSRMLS_CC, key.h); + return (slot) ? slot->value : NULL; +} +/* }}} */ + +/* {{{ apc_cache_user_find */ +apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC) +{ + slot_t** slot; + volatile apc_cache_entry_t* value = NULL; + unsigned long h; + + if(apc_cache_busy(cache)) + { + /* cache cleanup in progress */ + return NULL; + } + + CACHE_RDLOCK(cache); + + h = string_nhash_8(strkey, keylen); + + slot = &cache->slots[h % cache->num_slots]; + + while (*slot) { + if ((h == (*slot)->key.h) && + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { + /* Check to make sure this entry isn't expired by a hard TTL */ + if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) { + #if (USE_READ_LOCKS == 0) + /* this is merely a memory-friendly optimization, if we do have a write-lock + * might as well move this to the deleted_list right-away. Otherwise an insert + * of the same key wil do it (or an expunge, *eventually*). + */ + remove_slot(cache, slot TSRMLS_CC); + #endif + CACHE_FAST_INC(cache, cache->header->num_misses); + CACHE_RDUNLOCK(cache); + return NULL; + } + /* Otherwise we are fine, increase counters and return the cache entry */ + CACHE_SAFE_INC(cache, (*slot)->num_hits); + CACHE_SAFE_INC(cache, (*slot)->value->ref_count); + (*slot)->access_time = t; + + CACHE_FAST_INC(cache, cache->header->num_hits); + value = (*slot)->value; + CACHE_RDUNLOCK(cache); + return (apc_cache_entry_t*)value; + } + slot = &(*slot)->next; + } + + CACHE_FAST_INC(cache, cache->header->num_misses); + CACHE_RDUNLOCK(cache); + return NULL; +} +/* }}} */ + +/* {{{ apc_cache_user_exists */ +apc_cache_entry_t* apc_cache_user_exists(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC) +{ + slot_t** slot; + volatile apc_cache_entry_t* value = NULL; + unsigned long h; + + if(apc_cache_busy(cache)) + { + /* cache cleanup in progress */ + return NULL; + } + + CACHE_RDLOCK(cache); + + h = string_nhash_8(strkey, keylen); + + slot = &cache->slots[h % cache->num_slots]; + + while (*slot) { + if ((h == (*slot)->key.h) && + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { + /* Check to make sure this entry isn't expired by a hard TTL */ + if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) { + CACHE_UNLOCK(cache); + return NULL; + } + /* Return the cache entry ptr */ + value = (*slot)->value; + CACHE_RDUNLOCK(cache); + return (apc_cache_entry_t*)value; + } + slot = &(*slot)->next; + } + CACHE_RDUNLOCK(cache); + return NULL; +} +/* }}} */ + +/* {{{ apc_cache_user_update */ +int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen, apc_cache_updater_t updater, void* data TSRMLS_DC) +{ + slot_t** slot; + int retval; + unsigned long h; + + if(apc_cache_busy(cache)) + { + /* cache cleanup in progress */ + return 0; + } + + CACHE_LOCK(cache); + + h = string_nhash_8(strkey, keylen); + slot = &cache->slots[h % cache->num_slots]; + + while (*slot) { + if ((h == (*slot)->key.h) && + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { + switch(Z_TYPE_P((*slot)->value->data.user.val) & ~IS_CONSTANT_INDEX) { + case IS_ARRAY: + case IS_CONSTANT_ARRAY: + case IS_OBJECT: + { + if(APCG(serializer)) { + retval = 0; + break; + } else { + /* fall through */ + } + } + /* fall through */ + default: + { + retval = updater(cache, (*slot)->value, data); + (*slot)->key.mtime = apc_time(); + } + break; + } + CACHE_UNLOCK(cache); + return retval; + } + slot = &(*slot)->next; + } + CACHE_UNLOCK(cache); + return 0; +} +/* }}} */ + +/* {{{ apc_cache_user_delete */ +int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC) +{ + slot_t** slot; + unsigned long h; + + CACHE_LOCK(cache); + + h = string_nhash_8(strkey, keylen); + + slot = &cache->slots[h % cache->num_slots]; + + while (*slot) { + if ((h == (*slot)->key.h) && + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { + remove_slot(cache, slot TSRMLS_CC); + CACHE_UNLOCK(cache); + return 1; + } + slot = &(*slot)->next; + } + + CACHE_UNLOCK(cache); + return 0; +} +/* }}} */ + +/* {{{ apc_cache_delete */ +int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC) +{ + slot_t** slot; + time_t t; + apc_cache_key_t key; + + t = apc_time(); + + /* try to create a cache key; if we fail, give up on caching */ + if (!apc_cache_make_file_key(&key, filename, PG(include_path), t TSRMLS_CC)) { + apc_warning("Could not stat file %s, unable to delete from cache." TSRMLS_CC, filename); + return -1; + } + + CACHE_LOCK(cache); + + if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots]; + else slot = &cache->slots[key.h % cache->num_slots]; + + while(*slot) { + if(key.type == (*slot)->key.type) { + if(key.type == APC_CACHE_KEY_FILE) { + if(key_equals((*slot)->key.data.file, key.data.file)) { + remove_slot(cache, slot TSRMLS_CC); + CACHE_UNLOCK(cache); + return 1; + } + } else { /* APC_CACHE_KEY_FPFILE */ + if(((*slot)->key.h == key.h) && + (!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1))) { + remove_slot(cache, slot TSRMLS_CC); + CACHE_UNLOCK(cache); + return 1; + } + } + } + slot = &(*slot)->next; + } + + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); + + CACHE_UNLOCK(cache); + return 0; + +} +/* }}} */ + +/* {{{ apc_cache_release */ +void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry TSRMLS_DC) +{ + CACHE_SAFE_DEC(cache, entry->ref_count); +} +/* }}} */ + +/* {{{ apc_cache_make_file_key */ +int apc_cache_make_file_key(apc_cache_key_t* key, + const char* filename, + const char* include_path, + time_t t + TSRMLS_DC) +{ + struct stat *tmp_buf=NULL; + struct apc_fileinfo_t *fileinfo = NULL; + int len; + + assert(key != NULL); + + if (!filename || !SG(request_info).path_translated) { + apc_debug("No filename and no path_translated - bailing\n" TSRMLS_CC); + goto cleanup; + } + + len = strlen(filename); + if(APCG(fpstat)==0) { + if(IS_ABSOLUTE_PATH(filename,len)) { + key->data.fpfile.fullpath = filename; + key->data.fpfile.fullpath_len = len; + key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len); + key->mtime = t; + key->type = APC_CACHE_KEY_FPFILE; + goto success; + } else if(APCG(canonicalize)) { + + fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC); + + if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) { + apc_warning("apc failed to locate %s - bailing" TSRMLS_CC, filename); + goto cleanup; + } + + if(!VCWD_REALPATH(fileinfo->fullpath, APCG(canon_path))) { + apc_warning("realpath failed to canonicalize %s - bailing" TSRMLS_CC, filename); + goto cleanup; + } + + key->data.fpfile.fullpath = APCG(canon_path); + key->data.fpfile.fullpath_len = strlen(APCG(canon_path)); + key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len); + key->mtime = t; + key->type = APC_CACHE_KEY_FPFILE; + goto success; + } + /* fall through to stat mode */ + } + + fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC); + + assert(fileinfo != NULL); + + if(!strcmp(SG(request_info).path_translated, filename)) { + tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */ + } + + if(tmp_buf) { + fileinfo->st_buf.sb = *tmp_buf; + } else { + if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) { + apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC, filename,SG(request_info).path_translated); + goto cleanup; + } + } + + if(APCG(max_file_size) < fileinfo->st_buf.sb.st_size) { + apc_debug("File is too big %s (%d - %ld) - bailing\n" TSRMLS_CC, filename,t,fileinfo->st_buf.sb.st_size); + goto cleanup; + } + + /* + * This is a bit of a hack. + * + * Here I am checking to see if the file is at least 2 seconds old. + * The idea is that if the file is currently being written to then its + * mtime is going to match or at most be 1 second off of the current + * request time and we want to avoid caching files that have not been + * completely written. Of course, people should be using atomic + * mechanisms to push files onto live web servers, but adding this + * tiny safety is easier than educating the world. This is now + * configurable, but the default is still 2 seconds. + */ + if(APCG(file_update_protection) && (t - fileinfo->st_buf.sb.st_mtime < APCG(file_update_protection)) && !APCG(force_file_update)) { + apc_debug("File is too new %s (%d - %d) - bailing\n" TSRMLS_CC,filename,t,fileinfo->st_buf.sb.st_mtime); + goto cleanup; + } + + key->data.file.device = fileinfo->st_buf.sb.st_dev; + key->data.file.inode = fileinfo->st_buf.sb.st_ino; + key->h = (unsigned long) key->data.file.device + (unsigned long) key->data.file.inode; + + /* + * If working with content management systems that like to munge the mtime, + * it might be appropriate to key off of the ctime to be immune to systems + * that try to backdate a template. If the mtime is set to something older + * than the previous mtime of a template we will obviously never see this + * "older" template. At some point the Smarty templating system did this. + * I generally disagree with using the ctime here because you lose the + * ability to warm up new content by saving it to a temporary file, hitting + * it once to cache it and then renaming it into its permanent location so + * set the apc.stat_ctime=true to enable this check. + */ + if(APCG(stat_ctime)) { + key->mtime = (fileinfo->st_buf.sb.st_ctime > fileinfo->st_buf.sb.st_mtime) ? fileinfo->st_buf.sb.st_ctime : fileinfo->st_buf.sb.st_mtime; + } else { + key->mtime = fileinfo->st_buf.sb.st_mtime; + } + key->type = APC_CACHE_KEY_FILE; + +success: + + if(fileinfo != NULL) { + apc_php_free(fileinfo TSRMLS_CC); + } + + return 1; + +cleanup: + + if(fileinfo != NULL) { + apc_php_free(fileinfo TSRMLS_CC); + } + + return 0; +} +/* }}} */ + +/* {{{ apc_cache_make_user_key */ +int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t) +{ + assert(key != NULL); + + if (!identifier) + return 0; + + key->data.user.identifier = identifier; + key->data.user.identifier_len = identifier_len; + key->h = string_nhash_8(key->data.user.identifier, key->data.user.identifier_len); + key->mtime = t; + key->type = APC_CACHE_KEY_USER; + return 1; +} +/* }}} */ + +/* {{{ apc_cache_make_file_entry */ +apc_cache_entry_t* apc_cache_make_file_entry(const char* filename, + zend_op_array* op_array, + apc_function_t* functions, + apc_class_t* classes, + apc_context_t* ctxt + TSRMLS_DC) +{ + apc_cache_entry_t* entry; + apc_pool* pool = ctxt->pool; + + entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t)); + if (!entry) return NULL; + + entry->data.file.filename = apc_pstrdup(filename, pool TSRMLS_CC); + if(!entry->data.file.filename) { + apc_debug("apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n" TSRMLS_CC); + return NULL; + } + apc_debug("apc_cache_make_file_entry: entry->data.file.filename is [%s]\n" TSRMLS_CC,entry->data.file.filename); + entry->data.file.op_array = op_array; + entry->data.file.functions = functions; + entry->data.file.classes = classes; + + entry->data.file.halt_offset = apc_file_halt_offset(filename TSRMLS_CC); + + entry->type = APC_CACHE_ENTRY_FILE; + entry->ref_count = 0; + entry->mem_size = 0; + entry->pool = pool; + return entry; +} +/* }}} */ + +/* {{{ apc_cache_store_zval */ +zval* apc_cache_store_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) +{ + if (Z_TYPE_P(src) == IS_ARRAY) { + /* Maintain a list of zvals we've copied to properly handle recursive structures */ + zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0); + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); + zend_hash_destroy(&APCG(copied_zvals)); + APCG(copied_zvals).nTableSize=0; + } else { + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); + } + + + return dst; +} +/* }}} */ + +/* {{{ apc_cache_fetch_zval */ +zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) +{ + if (Z_TYPE_P(src) == IS_ARRAY) { + /* Maintain a list of zvals we've copied to properly handle recursive structures */ + zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0); + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); + zend_hash_destroy(&APCG(copied_zvals)); + APCG(copied_zvals).nTableSize=0; + } else { + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC); + } + + + return dst; +} +/* }}} */ + +/* {{{ apc_cache_make_user_entry */ +apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, apc_context_t* ctxt, const unsigned int ttl TSRMLS_DC) +{ + apc_cache_entry_t* entry; + apc_pool* pool = ctxt->pool; + + entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t)); + if (!entry) return NULL; + + entry->data.user.info = apc_pmemcpy(info, info_len, pool TSRMLS_CC); + entry->data.user.info_len = info_len; + if(!entry->data.user.info) { + return NULL; + } + entry->data.user.val = apc_cache_store_zval(NULL, val, ctxt TSRMLS_CC); + if(!entry->data.user.val) { + return NULL; + } + INIT_PZVAL(entry->data.user.val); + entry->data.user.ttl = ttl; + entry->type = APC_CACHE_ENTRY_USER; + entry->ref_count = 0; + entry->mem_size = 0; + entry->pool = pool; + return entry; +} +/* }}} */ + +/* {{{ */ +static zval* apc_cache_link_info(apc_cache_t *cache, slot_t* p TSRMLS_DC) +{ + zval *link = NULL; + char md5str[33]; + + ALLOC_INIT_ZVAL(link); + + if(!link) { + return NULL; + } + + array_init(link); + + if(p->value->type == APC_CACHE_ENTRY_FILE) { + add_assoc_string(link, "type", "file", 1); + if(p->key.type == APC_CACHE_KEY_FILE) { + + #ifdef PHP_WIN32 + { + char buf[20]; + sprintf(buf, "%I64d", p->key.data.file.device); + add_assoc_string(link, "device", buf, 1); + + sprintf(buf, "%I64d", p->key.data.file.inode); + add_assoc_string(link, "inode", buf, 1); + } + #else + add_assoc_long(link, "device", p->key.data.file.device); + add_assoc_long(link, "inode", p->key.data.file.inode); + #endif + + add_assoc_string(link, "filename", p->value->data.file.filename, 1); + } else { /* This is a no-stat fullpath file entry */ + add_assoc_long(link, "device", 0); + add_assoc_long(link, "inode", 0); + add_assoc_string(link, "filename", (char*)p->key.data.fpfile.fullpath, 1); + } + if (APCG(file_md5)) { + make_digest(md5str, p->key.md5); + add_assoc_string(link, "md5", md5str, 1); + } + } else if(p->value->type == APC_CACHE_ENTRY_USER) { + add_assoc_stringl(link, "info", p->value->data.user.info, p->value->data.user.info_len-1, 1); + add_assoc_long(link, "ttl", (long)p->value->data.user.ttl); + add_assoc_string(link, "type", "user", 1); + } + + add_assoc_double(link, "num_hits", (double)p->num_hits); + add_assoc_long(link, "mtime", p->key.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->value->ref_count); + add_assoc_long(link, "mem_size", p->value->mem_size); + + return link; +} +/* }}} */ + +/* {{{ apc_cache_info */ +zval* apc_cache_info(apc_cache_t* cache, zend_bool limited TSRMLS_DC) +{ + zval *info = NULL; + zval *list = NULL; + zval *deleted_list = NULL; + zval *slots = NULL; + slot_t* p; + int i, j; + + if(!cache) return NULL; + + CACHE_RDLOCK(cache); + + ALLOC_INIT_ZVAL(info); + + if(!info) { + CACHE_RDUNLOCK(cache); + return NULL; + } + + array_init(info); + add_assoc_long(info, "num_slots", cache->num_slots); + add_assoc_long(info, "ttl", cache->ttl); + + add_assoc_double(info, "num_hits", (double)cache->header->num_hits); + add_assoc_double(info, "num_misses", (double)cache->header->num_misses); + add_assoc_double(info, "num_inserts", (double)cache->header->num_inserts); + add_assoc_double(info, "expunges", (double)cache->header->expunges); + + add_assoc_long(info, "start_time", cache->header->start_time); + add_assoc_double(info, "mem_size", (double)cache->header->mem_size); + add_assoc_long(info, "num_entries", cache->header->num_entries); +#ifdef MULTIPART_EVENT_FORMDATA + add_assoc_long(info, "file_upload_progress", 1); +#else + add_assoc_long(info, "file_upload_progress", 0); +#endif +#if APC_MMAP + add_assoc_stringl(info, "memory_type", "mmap", sizeof("mmap")-1, 1); +#else + add_assoc_stringl(info, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1); +#endif + add_assoc_stringl(info, "locking_type", APC_LOCK_TYPE, sizeof(APC_LOCK_TYPE)-1, 1); + + if(!limited) { + /* For each hashtable slot */ + ALLOC_INIT_ZVAL(list); + array_init(list); + + ALLOC_INIT_ZVAL(slots); + array_init(slots); + + for (i = 0; i < cache->num_slots; i++) { + p = cache->slots[i]; + j = 0; + for (; p != NULL; p = p->next) { + zval *link = apc_cache_link_info(cache, p TSRMLS_CC); + add_next_index_zval(list, link); + j++; + } + add_next_index_long(slots, j); + } + + /* For each slot pending deletion */ + ALLOC_INIT_ZVAL(deleted_list); + array_init(deleted_list); + + for (p = cache->header->deleted_list; p != NULL; p = p->next) { + zval *link = apc_cache_link_info(cache, p TSRMLS_CC); + add_next_index_zval(deleted_list, link); + } + + add_assoc_zval(info, "cache_list", list); + add_assoc_zval(info, "deleted_list", deleted_list); + add_assoc_zval(info, "slot_distribution", slots); + } + + CACHE_RDUNLOCK(cache); + return info; +} +/* }}} */ + +/* {{{ apc_cache_unlock */ +void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC) +{ + CACHE_UNLOCK(cache); +} +/* }}} */ + +/* {{{ apc_cache_busy */ +zend_bool apc_cache_busy(apc_cache_t* cache) +{ + return cache->header->busy; +} +/* }}} */ + +/* {{{ apc_cache_is_last_key */ +zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t TSRMLS_DC) +{ + apc_keyid_t *lastkey = &cache->header->lastkey; + unsigned int keylen = key->data.user.identifier_len; +#ifdef ZTS + THREAD_T tid = tsrm_thread_id(); + #define FROM_DIFFERENT_THREAD(k) (memcmp(&((k)->tid), &tid, sizeof(THREAD_T))!=0) +#else + pid_t pid = getpid(); + #define FROM_DIFFERENT_THREAD(k) (pid != (k)->pid) +#endif + + + /* unlocked reads, but we're not shooting for 100% success with this */ + if(lastkey->h == key->h && keylen == lastkey->keylen) { + if(lastkey->mtime == t && FROM_DIFFERENT_THREAD(lastkey)) { + /* potential cache slam */ + if(APCG(slam_defense)) { + apc_debug("Potential cache slam averted for key '%s'" TSRMLS_CC, key->data.user.identifier); + return 1; + } + } + } + + return 0; +} +/* }}} */ + +#if NONBLOCKING_LOCK_AVAILABLE +/* {{{ apc_cache_write_lock */ +zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC) +{ + return apc_lck_nb_lock(cache->header->wrlock); +} +/* }}} */ + +/* {{{ apc_cache_write_unlock */ +void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC) +{ + apc_lck_unlock(cache->header->wrlock); +} +/* }}} */ +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_cache.h ^ |
(renamed from APC-3.1.8/apc_cache.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_cache.h ^ |
(renamed from APC-3.1.8/apc_cache.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.c ^ |
(renamed from APC-3.1.8/apc_compile.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.c ^ |
(renamed from APC-3.1.8/apc_compile.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.h ^ |
(renamed from APC-3.1.8/apc_compile.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_compile.h ^ |
(renamed from APC-3.1.8/apc_compile.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.c ^ |
(renamed from APC-3.1.8/apc_debug.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.c ^ |
(renamed from APC-3.1.8/apc_debug.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.h ^ |
(renamed from APC-3.1.8/apc_debug.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_debug.h ^ |
(renamed from APC-3.1.8/apc_debug.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.c ^ |
(renamed from APC-3.1.8/apc_fcntl.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.c ^ |
(renamed from APC-3.1.8/apc_fcntl.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.h ^ |
(renamed from APC-3.1.8/apc_fcntl.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl.h ^ |
(renamed from APC-3.1.8/apc_fcntl.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl_win32.c ^ |
(renamed from APC-3.1.8/apc_fcntl_win32.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_fcntl_win32.c ^ |
(renamed from APC-3.1.8/apc_fcntl_win32.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_globals.h ^ |
(renamed from APC-3.1.8/apc_globals.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_globals.h ^ |
(renamed from APC-3.1.8/apc_globals.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.c ^ |
(renamed from APC-3.1.8/apc_iterator.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.c ^ |
(renamed from APC-3.1.8/apc_iterator.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.h ^ |
(renamed from APC-3.1.8/apc_iterator.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_iterator.h ^ |
(renamed from APC-3.1.8/apc_iterator.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_lock.h ^ |
(renamed from APC-3.1.8/apc_lock.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_lock.h ^ |
(renamed from APC-3.1.8/apc_lock.h) | ||
[+] | Added | APC-3.1.9.tar.bz2/APC-3.1.9/apc_main.c ^ |
@@ -0,0 +1,1026 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2011 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 <dcowgill@communityconnect.com> | + | Rasmus Lerdorf <rasmus@php.net> | + | Arun C. Murthy <arunc@yahoo-inc.com> | + | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> | + +----------------------------------------------------------------------+ + + 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: apc_main.c 309002 2011-03-07 19:50:18Z pajoye $ */ + +#include "apc_php.h" +#include "apc_main.h" +#include "apc.h" +#include "apc_lock.h" +#include "apc_cache.h" +#include "apc_compile.h" +#include "apc_globals.h" +#include "apc_sma.h" +#include "apc_stack.h" +#include "apc_zend.h" +#include "apc_pool.h" +#include "apc_string.h" +#include "SAPI.h" +#include "php_scandir.h" +#include "ext/standard/php_var.h" +#include "ext/standard/md5.h" + +#define APC_MAX_SERIALIZERS 16 + +/* {{{ module variables */ + +/* pointer to the original Zend engine compile_file function */ +typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC); +static zend_compile_t *old_compile_file; +static apc_serializer_t apc_serializers[APC_MAX_SERIALIZERS] = {{0,}}; + +/* }}} */ + +/* {{{ get/set old_compile_file (to interact with other extensions that need the compile hook) */ +static zend_compile_t* set_compile_hook(zend_compile_t *ptr) +{ + zend_compile_t *retval = old_compile_file; + + if (ptr != NULL) old_compile_file = ptr; + return retval; +} +/* }}} */ + +/* {{{ install_function */ +static int install_function(apc_function_t fn, apc_context_t* ctxt, int lazy TSRMLS_DC) +{ + int status; + +#if APC_HAVE_LOOKUP_HOOKS + if(lazy && fn.name[0] != '\0' && strncmp(fn.name, "__autoload", fn.name_len) != 0) { + status = zend_hash_add(APCG(lazy_function_table), + fn.name, + fn.name_len+1, + &fn, + sizeof(apc_function_t), + NULL); +#else + if(0) { +#endif + } else { + zend_function *func = apc_copy_function_for_execution(fn.function, ctxt TSRMLS_CC); + status = zend_hash_add(EG(function_table), + fn.name, + fn.name_len+1, + func, + sizeof(fn.function[0]), + NULL); + efree(func); + } + + if (status == FAILURE) { + /* apc_error("Cannot redeclare %s()" TSRMLS_CC, fn.name); */ + } + + return status; +} +/* }}} */ + +/* {{{ apc_lookup_function_hook */ +int apc_lookup_function_hook(char *name, int len, ulong hash, zend_function **fe) { + apc_function_t *fn; + int status = FAILURE; + apc_context_t ctxt = {0,}; + TSRMLS_FETCH(); + + ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC); + ctxt.copy = APC_COPY_OUT_OPCODE; + + if(zend_hash_quick_find(APCG(lazy_function_table), name, len, hash, (void**)&fn) == SUCCESS) { + *fe = apc_copy_function_for_execution(fn->function, &ctxt TSRMLS_CC); + status = zend_hash_add(EG(function_table), + fn->name, + fn->name_len+1, + *fe, + sizeof(zend_function), + NULL); + } + + return status; +} +/* }}} */ + +/* {{{ install_class */ +static int install_class(apc_class_t cl, apc_context_t* ctxt, int lazy TSRMLS_DC) +{ + zend_class_entry* class_entry = cl.class_entry; + zend_class_entry* parent = NULL; + int status; + zend_class_entry** allocated_ce = NULL; + + /* Special case for mangled names. Mangled names are unique to a file. + * There is no way two classes with the same mangled name will occur, + * unless a file is included twice. And if in case, a file is included + * twice, all mangled name conflicts can be ignored and the class redeclaration + * error may be deferred till runtime of the corresponding DECLARE_CLASS + * calls. + */ + + if(cl.name_len != 0 && cl.name[0] == '\0') { + if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) { + return SUCCESS; + } + } + + if(lazy && cl.name_len != 0 && cl.name[0] != '\0') { + status = zend_hash_add(APCG(lazy_class_table), + cl.name, + cl.name_len+1, + &cl, + sizeof(apc_class_t), + NULL); + if(status == FAILURE) { + zend_error(E_ERROR, "Cannot redeclare class %s", cl.name); + } + return status; + } + + /* + * XXX: We need to free this somewhere... + */ + allocated_ce = apc_php_malloc(sizeof(zend_class_entry*) TSRMLS_CC); + + if(!allocated_ce) { + return FAILURE; + } + + *allocated_ce = + class_entry = + apc_copy_class_entry_for_execution(cl.class_entry, ctxt TSRMLS_CC); + + + /* restore parent class pointer for compile-time inheritance */ + if (cl.parent_name != NULL) { + zend_class_entry** parent_ptr = NULL; + /* + * __autoload brings in the old issues with mixed inheritance. + * When a statically inherited class triggers autoload, it runs + * afoul of a potential require_once "parent.php" in the previous + * line, which when executed provides the parent class, but right + * now goes and hits __autoload which could fail. + * + * missing parent == re-compile. + * + * whether __autoload is enabled or not, because __autoload errors + * cause php to die. + * + * Aside: Do NOT pass *strlen(cl.parent_name)+1* because + * zend_lookup_class_ex does it internally anyway! + */ + status = zend_lookup_class_ex(cl.parent_name, + strlen(cl.parent_name), +#ifdef ZEND_ENGINE_2_4 + NULL, +#endif + 0, + &parent_ptr TSRMLS_CC); + if (status == FAILURE) { + if(APCG(report_autofilter)) { + apc_warning("Dynamic inheritance detected for class %s" TSRMLS_CC, cl.name); + } + class_entry->parent = NULL; + return status; + } + else { + parent = *parent_ptr; + class_entry->parent = parent; + zend_do_inheritance(class_entry, parent TSRMLS_CC); + } + + + } + + status = zend_hash_add(EG(class_table), + cl.name, + cl.name_len+1, + allocated_ce, + sizeof(zend_class_entry*), + NULL); + + if (status == FAILURE) { + apc_error("Cannot redeclare class %s" TSRMLS_CC, cl.name); + } + return status; +} +/* }}} */ + +/* {{{ apc_lookup_class_hook */ +int apc_lookup_class_hook(char *name, int len, ulong hash, zend_class_entry ***ce) { + + apc_class_t *cl; + apc_context_t ctxt = {0,}; + TSRMLS_FETCH(); + + if(zend_is_compiling(TSRMLS_C)) { return FAILURE; } + + if(zend_hash_quick_find(APCG(lazy_class_table), name, len, hash, (void**)&cl) == FAILURE) { + return FAILURE; + } + + ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC); + ctxt.copy = APC_COPY_OUT_OPCODE; + + if(install_class(*cl, &ctxt, 0 TSRMLS_CC) == FAILURE) { + apc_warning("apc_lookup_class_hook: could not install %s" TSRMLS_CC, name); + return FAILURE; + } + + if(zend_hash_quick_find(EG(class_table), name, len, hash, (void**)ce) == FAILURE) { + apc_warning("apc_lookup_class_hook: known error trying to fetch class %s" TSRMLS_CC, name); + return FAILURE; + } + + return SUCCESS; + +} +/* }}} */ + +/* {{{ uninstall_class */ +static int uninstall_class(apc_class_t cl TSRMLS_DC) +{ + int status; + + status = zend_hash_del(EG(class_table), + cl.name, + cl.name_len+1); + if (status == FAILURE) { + apc_error("Cannot delete class %s" TSRMLS_CC, cl.name); + } + return status; +} +/* }}} */ + +/* {{{ copy_function_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */ +static int copy_function_name(apc_function_t *pf TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +{ + zval *internal_ar = va_arg(args, zval *), + *user_ar = va_arg(args, zval *); + zend_function *func = pf->function; + + if (hash_key->nKeyLength == 0 || hash_key->arKey[0] == 0) { + return 0; + } + + if (func->type == ZEND_INTERNAL_FUNCTION) { + add_next_index_stringl(internal_ar, hash_key->arKey, hash_key->nKeyLength-1, 1); + } else if (func->type == ZEND_USER_FUNCTION) { + add_next_index_stringl(user_ar, hash_key->arKey, hash_key->nKeyLength-1, 1); + } + + return 0; +} + +/* {{{ copy_class_or_interface_name (taken from zend_builtin_functions.c to ensure future compatibility with APC) */ +static int copy_class_or_interface_name(apc_class_t *cl TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +{ + zval *array = va_arg(args, zval *); + zend_uint mask = va_arg(args, zend_uint); + zend_uint comply = va_arg(args, zend_uint); + zend_uint comply_mask = (comply)? mask:0; + zend_class_entry *ce = cl->class_entry; + + if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0) + && (comply_mask == (ce->ce_flags & mask))) { + add_next_index_stringl(array, ce->name, ce->name_length, 1); + } + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +/* }}} */ + +/* {{{ apc_defined_function_hook */ +int apc_defined_function_hook(zval *internal, zval *user) { + TSRMLS_FETCH(); + zend_hash_apply_with_arguments(APCG(lazy_function_table) +#ifdef ZEND_ENGINE_2_3 + TSRMLS_CC +#endif + ,(apply_func_args_t) copy_function_name, 2, internal, user); + return 1; +} +/* }}} */ + +/* {{{ apc_declared_class_hook */ +int apc_declared_class_hook(zval *classes, zend_uint mask, zend_uint comply) { + TSRMLS_FETCH(); + zend_hash_apply_with_arguments(APCG(lazy_class_table) +#ifdef ZEND_ENGINE_2_3 + TSRMLS_CC +#endif + , (apply_func_args_t) copy_class_or_interface_name, 3, classes, mask, comply); + return 1; +} +/* }}} */ + +/* {{{ cached_compile */ +static zend_op_array* cached_compile(zend_file_handle* h, + int type, + apc_context_t* ctxt TSRMLS_DC) +{ + apc_cache_entry_t* cache_entry; + int i, ii; + + cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack)); + assert(cache_entry != NULL); + + if (cache_entry->data.file.classes) { + int lazy_classes = APCG(lazy_classes); + for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { + if(install_class(cache_entry->data.file.classes[i], ctxt, lazy_classes TSRMLS_CC) == FAILURE) { + goto default_compile; + } + } + } + + if (cache_entry->data.file.functions) { + int lazy_functions = APCG(lazy_functions); + for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) { + install_function(cache_entry->data.file.functions[i], ctxt, lazy_functions TSRMLS_CC); + } + } + + apc_do_halt_compiler_register(cache_entry->data.file.filename, cache_entry->data.file.halt_offset TSRMLS_CC); + + + return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array, ctxt TSRMLS_CC); + +default_compile: + + if(cache_entry->data.file.classes) { + for(ii = 0; ii < i ; ii++) { + uninstall_class(cache_entry->data.file.classes[ii] TSRMLS_CC); + } + } + + apc_stack_pop(APCG(cache_stack)); /* pop out cache_entry */ + + apc_cache_release(apc_cache, cache_entry TSRMLS_CC); + + /* cannot free up cache data yet, it maybe in use */ + + return NULL; +} +/* }}} */ + +/* {{{ apc_compile_cache_entry */ +zend_bool apc_compile_cache_entry(apc_cache_key_t key, zend_file_handle* h, int type, time_t t, zend_op_array** op_array, apc_cache_entry_t** cache_entry TSRMLS_DC) { + int num_functions, num_classes; + apc_function_t* alloc_functions; + zend_op_array* alloc_op_array; + apc_class_t* alloc_classes; + char *path; + apc_context_t ctxt; + + /* remember how many functions and classes existed before compilation */ + num_functions = zend_hash_num_elements(CG(function_table)); + num_classes = zend_hash_num_elements(CG(class_table)); + + /* compile the file using the default compile function, * + * we set *op_array here so we return opcodes during * + * a failure. We should not return prior to this line. */ + *op_array = old_compile_file(h, type TSRMLS_CC); + if (*op_array == NULL) { + return FAILURE; + } + + ctxt.pool = apc_pool_create(APC_MEDIUM_POOL, apc_sma_malloc, apc_sma_free, + apc_sma_protect, apc_sma_unprotect TSRMLS_CC); + if (!ctxt.pool) { + apc_warning("Unable to allocate memory for pool." TSRMLS_CC); + return FAILURE; + } + ctxt.copy = APC_COPY_IN_OPCODE; + + if(APCG(file_md5)) { + int n; + unsigned char buf[1024]; + PHP_MD5_CTX context; + php_stream *stream; + char *filename; + + if(h->opened_path) { + filename = h->opened_path; + } else { + filename = h->filename; + } + stream = php_stream_open_wrapper(filename, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL); + if(stream) { + PHP_MD5Init(&context); + while((n = php_stream_read(stream, (char*)buf, sizeof(buf))) > 0) { + PHP_MD5Update(&context, buf, n); + } + PHP_MD5Final(key.md5, &context); + php_stream_close(stream); + if(n<0) { + apc_warning("Error while reading '%s' for md5 generation." TSRMLS_CC, filename); + } + } else { + apc_warning("Unable to open '%s' for md5 generation." TSRMLS_CC, filename); + } + } + + if(!(alloc_op_array = apc_copy_op_array(NULL, *op_array, &ctxt TSRMLS_CC))) { + goto freepool; + } + + if(!(alloc_functions = apc_copy_new_functions(num_functions, &ctxt TSRMLS_CC))) { + goto freepool; + } + if(!(alloc_classes = apc_copy_new_classes(*op_array, num_classes, &ctxt TSRMLS_CC))) { + goto freepool; + } + + path = h->opened_path; + if(!path && key.type == APC_CACHE_KEY_FPFILE) path = (char*)key.data.fpfile.fullpath; + if(!path) path=h->filename; + + apc_debug("2. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename); + + if(!(*cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes, &ctxt TSRMLS_CC))) { + goto freepool; + } + + return SUCCESS; + +freepool: + apc_pool_destroy(ctxt.pool TSRMLS_CC); + ctxt.pool = NULL; + + return FAILURE; + +} +/* }}} */ + +/* {{{ my_compile_file + Overrides zend_compile_file */ +static zend_op_array* my_compile_file(zend_file_handle* h, + int type TSRMLS_DC) +{ + apc_cache_key_t key; + apc_cache_entry_t* cache_entry; + zend_op_array* op_array = NULL; + time_t t; + apc_context_t ctxt = {0,}; + int bailout=0; + const char* filename = NULL; + + if (!APCG(enabled) || apc_cache_busy(apc_cache)) { + return old_compile_file(h, type TSRMLS_CC); + } + + if(h->opened_path) { + filename = h->opened_path; + } else { + filename = h->filename; + } + + /* check our regular expression filters */ + if (APCG(filters) && APCG(compiled_filters) && filename) { + int ret = apc_regex_match_array(APCG(compiled_filters), filename); + + if(ret == APC_NEGATIVE_MATCH || (ret != APC_POSITIVE_MATCH && !APCG(cache_by_default))) { + return old_compile_file(h, type TSRMLS_CC); + } + } else if(!APCG(cache_by_default)) { + return old_compile_file(h, type TSRMLS_CC); + } + APCG(current_cache) = apc_cache; + + + t = apc_time(); + + apc_debug("1. h->opened_path=[%s] h->filename=[%s]\n" TSRMLS_CC, h->opened_path?h->opened_path:"null",h->filename); + + /* try to create a cache key; if we fail, give up on caching */ + if (!apc_cache_make_file_key(&key, h->filename, PG(include_path), t TSRMLS_CC)) { + return old_compile_file(h, type TSRMLS_CC); + } + + if(!APCG(force_file_update)) { + /* search for the file in the cache */ + cache_entry = apc_cache_find(apc_cache, key, t TSRMLS_CC); + ctxt.force_update = 0; + } else { + cache_entry = NULL; + ctxt.force_update = 1; + } + + if (cache_entry != NULL) { + int dummy = 1; + + ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, + apc_sma_protect, apc_sma_unprotect TSRMLS_CC); + if (!ctxt.pool) { + apc_warning("Unable to allocate memory for pool." TSRMLS_CC); + return old_compile_file(h, type TSRMLS_CC); + } + ctxt.copy = APC_COPY_OUT_OPCODE; + + zend_hash_add(&EG(included_files), cache_entry->data.file.filename, + strlen(cache_entry->data.file.filename)+1, + (void *)&dummy, sizeof(int), NULL); + + apc_stack_push(APCG(cache_stack), cache_entry TSRMLS_CC); + op_array = cached_compile(h, type, &ctxt TSRMLS_CC); + + if(op_array) { +#ifdef APC_FILEHITS + /* If the file comes from the cache, add it to the global request file list */ + add_next_index_string(APCG(filehits), h->filename, 1); +#endif + /* this is an unpool, which has no cleanup - this only free's the pool header */ + apc_pool_destroy(ctxt.pool TSRMLS_CC); + + /* We might leak fds without this hack */ + if (h->type != ZEND_HANDLE_FILENAME) { + zend_llist_add_element(&CG(open_files), h); + } + return op_array; + } + if(APCG(report_autofilter)) { + apc_warning("Autofiltering %s" TSRMLS_CC, + (h->opened_path ? h->opened_path : h->filename)); + apc_warning("Recompiling %s" TSRMLS_CC, cache_entry->data.file.filename); + } + /* TODO: check what happens with EG(included_files) */ + } + + /* Make sure the mtime reflects the files last known mtime, and we respect max_file_size in the case of fpstat==0 */ + if(key.type == APC_CACHE_KEY_FPFILE) { + apc_fileinfo_t fileinfo; + struct stat *tmp_buf = NULL; + if(!strcmp(SG(request_info).path_translated, h->filename)) { + tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */ + } + if(tmp_buf) { + fileinfo.st_buf.sb = *tmp_buf; + } else { + if (apc_search_paths(h->filename, PG(include_path), &fileinfo TSRMLS_CC) != 0) { + apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC,h->filename,SG(request_info).path_translated); + return old_compile_file(h, type TSRMLS_CC); + } + } + if (APCG(max_file_size) < fileinfo.st_buf.sb.st_size) { + apc_debug("File is too big %s (%ld) - bailing\n" TSRMLS_CC, h->filename, fileinfo.st_buf.sb.st_size); + return old_compile_file(h, type TSRMLS_CC); + } + key.mtime = fileinfo.st_buf.sb.st_mtime; + } + + HANDLE_BLOCK_INTERRUPTIONS(); + +#if NONBLOCKING_LOCK_AVAILABLE + if(APCG(write_lock)) { + if(!apc_cache_write_lock(apc_cache TSRMLS_CC)) { + HANDLE_UNBLOCK_INTERRUPTIONS(); + return old_compile_file(h, type TSRMLS_CC); + } + } +#endif + + zend_try { + if (apc_compile_cache_entry(key, h, type, t, &op_array, &cache_entry TSRMLS_CC) == SUCCESS) { + ctxt.pool = cache_entry->pool; + ctxt.copy = APC_COPY_IN_OPCODE; + if (apc_cache_insert(apc_cache, key, cache_entry, &ctxt, t TSRMLS_CC) != 1) { + apc_pool_destroy(ctxt.pool TSRMLS_CC); + ctxt.pool = NULL; + } + } + } zend_catch { + bailout=1; /* in the event of a bailout, ensure we don't create a dead-lock */ + } zend_end_try(); + + APCG(current_cache) = NULL; + +#if NONBLOCKING_LOCK_AVAILABLE + if(APCG(write_lock)) { + apc_cache_write_unlock(apc_cache TSRMLS_CC); + } +#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + + if (bailout) zend_bailout(); + + return op_array; +} +/* }}} */ + +/* {{{ data preload */ + +extern int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC); + +static zval* data_unserialize(const char *filename TSRMLS_DC) +{ + zval* retval; + long len = 0; + struct stat sb; + char *contents, *tmp; + FILE *fp; + php_unserialize_data_t var_hash; + + if(VCWD_STAT(filename, &sb) == -1) { + return NULL; + } + + fp = fopen(filename, "rb"); + + len = sizeof(char)*sb.st_size; + + tmp = contents = malloc(len); + + if(!contents) { + return NULL; + } + + if(fread(contents, 1, len, fp) < 1) { + free(contents); + return NULL; + } + + MAKE_STD_ZVAL(retval); + + PHP_VAR_UNSERIALIZE_INIT(var_hash); + + /* I wish I could use json */ + if(!php_var_unserialize(&retval, (const unsigned char**)&tmp, (const unsigned char*)(contents+len), &var_hash TSRMLS_CC)) { + zval_ptr_dtor(&retval); + return NULL; + } + + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + + free(contents); + fclose(fp); + + return retval; +} + +static int apc_load_data(const char *data_file TSRMLS_DC) +{ + char *p; + char key[MAXPATHLEN] = {0,}; + unsigned int key_len; + zval *data; + + p = strrchr(data_file, DEFAULT_SLASH); + + if(p && p[1]) { + strlcpy(key, p+1, sizeof(key)); + p = strrchr(key, '.'); + + if(p) { + p[0] = '\0'; + key_len = strlen(key); + + data = data_unserialize(data_file TSRMLS_CC); + if(data) { + _apc_store(key, key_len, data, 0, 1 TSRMLS_CC); + } + return 1; + } + } + + return 0; +} + +static int apc_walk_dir(const char *path TSRMLS_DC) +{ + char file[MAXPATHLEN]={0,}; + int ndir, i; + char *p = NULL; + struct dirent **namelist = NULL; + + if ((ndir = php_scandir(path, &namelist, 0, php_alphasort)) > 0) + { + for (i = 0; i < ndir; i++) + { + /* check for extension */ + if (!(p = strrchr(namelist[i]->d_name, '.')) + || (p && strcmp(p, ".data"))) + { + free(namelist[i]); + continue; + } + snprintf(file, MAXPATHLEN, "%s%c%s", + path, DEFAULT_SLASH, namelist[i]->d_name); + if(!apc_load_data(file TSRMLS_CC)) + { + /* print error */ + } + free(namelist[i]); + } + free(namelist); + } + + return 1; +} + +void apc_data_preload(TSRMLS_D) +{ + if(!APCG(preload_path)) return; + + apc_walk_dir(APCG(preload_path) TSRMLS_CC); +} +/* }}} */ + +/* {{{ apc_serializer hooks */ +static int _apc_register_serializer(const char* name, apc_serialize_t serialize, + apc_unserialize_t unserialize, + void *config TSRMLS_DC) +{ + int i; + apc_serializer_t *serializer; + + for(i = 0; i < APC_MAX_SERIALIZERS; i++) { + serializer = &apc_serializers[i]; + if(!serializer->name) { + /* empty entry */ + serializer->name = name; /* assumed to be const */ + serializer->serialize = serialize; + serializer->unserialize = unserialize; + serializer->config = config; + apc_serializers[i+1].name = NULL; + return 1; + } + } + + return 0; +} + +apc_serializer_t* apc_find_serializer(const char* name TSRMLS_DC) +{ + int i; + apc_serializer_t *serializer; + + for(i = 0; i < APC_MAX_SERIALIZERS; i++) { + serializer = &apc_serializers[i]; + if(serializer->name && (strcmp(serializer->name, name) == 0)) { + return serializer; + } + } + return NULL; +} + +apc_serializer_t* apc_get_serializers(TSRMLS_D) +{ + return &(apc_serializers[0]); +} +/* }}} */ + +/* {{{ module init and shutdown */ + +int apc_module_init(int module_number TSRMLS_DC) +{ + /* apc initialization */ +#if APC_MMAP + apc_sma_init(APCG(shm_segments), APCG(shm_size), APCG(mmap_file_mask) TSRMLS_CC); +#else + apc_sma_init(APCG(shm_segments), APCG(shm_size), NULL TSRMLS_CC); +#endif + apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl) TSRMLS_CC); + apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl) TSRMLS_CC); + + /* override compilation */ + old_compile_file = zend_compile_file; + zend_compile_file = my_compile_file; + REGISTER_LONG_CONSTANT("\000apc_magic", (long)&set_compile_hook, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("\000apc_compile_file", (long)&my_compile_file, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT(APC_SERIALIZER_CONSTANT, (long)&_apc_register_serializer, CONST_PERSISTENT | CONST_CS); + + /* test out the constant function pointer */ + apc_register_serializer("php", APC_SERIALIZER_NAME(php), APC_UNSERIALIZER_NAME(php), NULL TSRMLS_CC); + + assert(apc_serializers[0].name != NULL); + + apc_pool_init(); + + apc_data_preload(TSRMLS_C); + +#if APC_HAVE_LOOKUP_HOOKS + if(APCG(lazy_functions)) { + zend_set_lookup_function_hook(apc_lookup_function_hook TSRMLS_CC); + zend_set_defined_function_hook(apc_defined_function_hook TSRMLS_CC); + } + if(APCG(lazy_classes)) { + zend_set_lookup_class_hook(apc_lookup_class_hook TSRMLS_CC); + zend_set_declared_class_hook(apc_declared_class_hook TSRMLS_CC); + } +#else + if(APCG(lazy_functions) || APCG(lazy_classes)) { + apc_warning("Lazy function/class loading not available with this version of PHP, please disable APC lazy loading." TSRMLS_CC); + APCG(lazy_functions) = APCG(lazy_classes) = 0; + } +#endif + +#ifdef ZEND_ENGINE_2_4 + apc_interned_strings_init(TSRMLS_C); +#endif + + APCG(initialized) = 1; + return 0; +} + +int apc_module_shutdown(TSRMLS_D) +{ + if (!APCG(initialized)) + return 0; + + /* restore compilation */ + zend_compile_file = old_compile_file; + + /* + * In case we got interrupted by a SIGTERM or something else during execution + * we may have cache entries left on the stack that we need to check to make + * sure that any functions or classes these may have added to the global function + * and class tables are removed before we blow away the memory that hold them. + * + * This is merely to remove memory leak warnings - as the process is terminated + * immediately after shutdown. The following while loop can be removed without + * affecting anything else. + */ + while (apc_stack_size(APCG(cache_stack)) > 0) { + int i; + apc_cache_entry_t* cache_entry = (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack)); + if (cache_entry->data.file.functions) { + for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) { + zend_hash_del(EG(function_table), + cache_entry->data.file.functions[i].name, + cache_entry->data.file.functions[i].name_len+1); + } + } + if (cache_entry->data.file.classes) { + for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { + zend_hash_del(EG(class_table), + cache_entry->data.file.classes[i].name, + cache_entry->data.file.classes[i].name_len+1); + } + } + apc_cache_release(apc_cache, cache_entry TSRMLS_CC); + } + + apc_cache_destroy(apc_cache TSRMLS_CC); + apc_cache_destroy(apc_user_cache TSRMLS_CC); + apc_sma_cleanup(TSRMLS_C); + +#ifdef ZEND_ENGINE_2_4 + apc_interned_strings_shutdown(TSRMLS_C); +#endif + + APCG(initialized) = 0; + return 0; +} + +/* }}} */ + +/* {{{ process init and shutdown */ +int apc_process_init(int module_number TSRMLS_DC) +{ + return 0; +} + +int apc_process_shutdown(TSRMLS_D) +{ + return 0; +} +/* }}} */ + + +/* {{{ apc_deactivate */ +static void apc_deactivate(TSRMLS_D) +{ + /* The execution stack was unwound, which prevented us from decrementing + * the reference counts on active cache entries in `my_execute`. + */ + while (apc_stack_size(APCG(cache_stack)) > 0) { + int i; + zend_class_entry* zce = NULL; + void ** centry = (void*)(&zce); + zend_class_entry** pzce = NULL; + + apc_cache_entry_t* cache_entry = + (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack)); + + if (cache_entry->data.file.classes) { + for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { + centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */ + if(zend_hash_find(EG(class_table), + cache_entry->data.file.classes[i].name, + cache_entry->data.file.classes[i].name_len+1, + (void**)centry) == FAILURE) + { + /* double inclusion of conditional classes ends up failing + * this lookup the second time around. + */ + continue; + } + + zce = *pzce; + + zend_hash_del(EG(class_table), + cache_entry->data.file.classes[i].name, + cache_entry->data.file.classes[i].name_len+1); + + apc_free_class_entry_after_execution(zce TSRMLS_CC); + } + } + apc_cache_release(apc_cache, cache_entry TSRMLS_CC); + } +} +/* }}} */ + +/* {{{ request init and shutdown */ + +int apc_request_init(TSRMLS_D) +{ + apc_stack_clear(APCG(cache_stack)); + if (!APCG(compiled_filters) && APCG(filters)) { + /* compile regex filters here to avoid race condition between MINIT of PCRE and APC. + * This should be moved to apc_cache_create() if this race condition between modules is resolved */ + APCG(compiled_filters) = apc_regex_compile_array(APCG(filters) TSRMLS_CC); + } + + if (!APCG(serializer) && APCG(serializer_name)) { + /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */ + APCG(serializer) = apc_find_serializer(APCG(serializer_name) TSRMLS_CC); + } + +#if APC_HAVE_LOOKUP_HOOKS + if(APCG(lazy_functions)) { + APCG(lazy_function_table) = emalloc(sizeof(HashTable)); + zend_hash_init(APCG(lazy_function_table), 0, NULL, NULL, 0); + } + if(APCG(lazy_classes)) { + APCG(lazy_class_table) = emalloc(sizeof(HashTable)); + zend_hash_init(APCG(lazy_class_table), 0, NULL, NULL, 0); + } +#endif + +#ifdef APC_FILEHITS + ALLOC_INIT_ZVAL(APCG(filehits)); + array_init(APCG(filehits)); +#endif + + return 0; +} + +int apc_request_shutdown(TSRMLS_D) +{ +#if APC_HAVE_LOOKUP_HOOKS + if(APCG(lazy_class_table)) { + zend_hash_destroy(APCG(lazy_class_table)); + efree(APCG(lazy_class_table)); + } + if(APCG(lazy_function_table)) { + zend_hash_destroy(APCG(lazy_function_table)); + efree(APCG(lazy_function_table)); + } +#endif + + apc_deactivate(TSRMLS_C); + +#ifdef APC_FILEHITS + zval_ptr_dtor(&APCG(filehits)); +#endif + return 0; +} + +/* }}} */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_main.h ^ |
(renamed from APC-3.1.8/apc_main.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_main.h ^ |
(renamed from APC-3.1.8/apc_main.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.c ^ |
(renamed from APC-3.1.8/apc_mmap.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.c ^ |
(renamed from APC-3.1.8/apc_mmap.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.h ^ |
(renamed from APC-3.1.8/apc_mmap.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_mmap.h ^ |
(renamed from APC-3.1.8/apc_mmap.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_php.h ^ |
(renamed from APC-3.1.8/apc_php.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_php.h ^ |
(renamed from APC-3.1.8/apc_php.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_php_pcre.h ^ |
(renamed from APC-3.1.8/apc_php_pcre.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_php_pcre.h ^ |
(renamed from APC-3.1.8/apc_php_pcre.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.c ^ |
(renamed from APC-3.1.8/apc_pool.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.c ^ |
(renamed from APC-3.1.8/apc_pool.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.h ^ |
(renamed from APC-3.1.8/apc_pool.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pool.h ^ |
(renamed from APC-3.1.8/apc_pool.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.c ^ |
(renamed from APC-3.1.8/apc_pthreadmutex.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.c ^ |
(renamed from APC-3.1.8/apc_pthreadmutex.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.h ^ |
(renamed from APC-3.1.8/apc_pthreadmutex.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadmutex.h ^ |
(renamed from APC-3.1.8/apc_pthreadmutex.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.c ^ |
(renamed from APC-3.1.8/apc_pthreadrwlock.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.c ^ |
(renamed from APC-3.1.8/apc_pthreadrwlock.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.h ^ |
(renamed from APC-3.1.8/apc_pthreadrwlock.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_pthreadrwlock.h ^ |
(renamed from APC-3.1.8/apc_pthreadrwlock.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_rfc1867.c ^ |
(renamed from APC-3.1.8/apc_rfc1867.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_rfc1867.c ^ |
(renamed from APC-3.1.8/apc_rfc1867.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.c ^ |
(renamed from APC-3.1.8/apc_sem.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.c ^ |
(renamed from APC-3.1.8/apc_sem.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.h ^ |
(renamed from APC-3.1.8/apc_sem.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sem.h ^ |
(renamed from APC-3.1.8/apc_sem.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_serializer.h ^ |
(renamed from APC-3.1.8/apc_serializer.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_serializer.h ^ |
(renamed from APC-3.1.8/apc_serializer.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.c ^ |
(renamed from APC-3.1.8/apc_shm.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.c ^ |
(renamed from APC-3.1.8/apc_shm.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.h ^ |
(renamed from APC-3.1.8/apc_shm.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_shm.h ^ |
(renamed from APC-3.1.8/apc_shm.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.c ^ |
(renamed from APC-3.1.8/apc_signal.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.c ^ |
(renamed from APC-3.1.8/apc_signal.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.h ^ |
(renamed from APC-3.1.8/apc_signal.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_signal.h ^ |
(renamed from APC-3.1.8/apc_signal.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.c ^ |
(renamed from APC-3.1.8/apc_sma.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.c ^ |
(renamed from APC-3.1.8/apc_sma.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.h ^ |
(renamed from APC-3.1.8/apc_sma.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_sma.h ^ |
(renamed from APC-3.1.8/apc_sma.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.c ^ |
(renamed from APC-3.1.8/apc_spin.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.c ^ |
(renamed from APC-3.1.8/apc_spin.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.h ^ |
(renamed from APC-3.1.8/apc_spin.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_spin.h ^ |
(renamed from APC-3.1.8/apc_spin.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.c ^ |
(renamed from APC-3.1.8/apc_stack.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.c ^ |
(renamed from APC-3.1.8/apc_stack.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.h ^ |
(renamed from APC-3.1.8/apc_stack.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_stack.h ^ |
(renamed from APC-3.1.8/apc_stack.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.c ^ |
(renamed from APC-3.1.8/apc_string.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.c ^ |
(renamed from APC-3.1.8/apc_string.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.h ^ |
(renamed from APC-3.1.8/apc_string.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_string.h ^ |
(renamed from APC-3.1.8/apc_string.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.c ^ |
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.c ^ |
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.h ^ |
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_windows_srwlock_kernel.h ^ |
(renamed from APC-3.1.8/apc_windows_srwlock_kernel.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.c ^ |
(renamed from APC-3.1.8/apc_zend.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.c ^ |
(renamed from APC-3.1.8/apc_zend.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.h ^ |
(renamed from APC-3.1.8/apc_zend.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/apc_zend.h ^ |
(renamed from APC-3.1.8/apc_zend.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/config.m4 ^ |
(renamed from APC-3.1.8/config.m4) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/config.m4 ^ |
(renamed from APC-3.1.8/config.m4) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/config.w32 ^ |
(renamed from APC-3.1.8/config.w32) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/config.w32 ^ |
(renamed from APC-3.1.8/config.w32) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.c ^ |
(renamed from APC-3.1.8/pgsql_s_lock.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.c ^ |
(renamed from APC-3.1.8/pgsql_s_lock.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.h ^ |
(renamed from APC-3.1.8/pgsql_s_lock.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/pgsql_s_lock.h ^ |
(renamed from APC-3.1.8/pgsql_s_lock.h) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/php_apc.c ^ |
(renamed from APC-3.1.8/php_apc.c) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/php_apc.c ^ |
(renamed from APC-3.1.8/php_apc.c) | ||
[+] | Added | APC-3.1.9.tar.bz2/APC-3.1.9/php_apc.h ^ |
@@ -0,0 +1,54 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2011 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 <dcowgill@communityconnect.com> | + | George Schlossnagle <george@omniti.com> | + | Rasmus Lerdorf <rasmus@php.net> | + +----------------------------------------------------------------------+ + + 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.h 311026 2011-05-14 22:09:47Z pajoye $ */ + +#ifndef PHP_APC_H +#define PHP_APC_H + +#include "apc_php.h" +#include "apc_globals.h" + +#define PHP_APC_VERSION "3.1.9" + +extern zend_module_entry apc_module_entry; +#define apc_module_ptr &apc_module_entry + +#define phpext_apc_ptr apc_module_ptr + +#endif /* PHP_APC_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_001.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_001.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_002.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_002.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_003.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_003.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_003.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_003.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_004.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_004.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_004.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_004.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_005.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_005.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc53_005.phpt ^ |
(renamed from APC-3.1.8/tests/apc53_005.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_001.phpt ^ |
(renamed from APC-3.1.8/tests/apc_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_001.phpt ^ |
(renamed from APC-3.1.8/tests/apc_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_002.phpt ^ |
(renamed from APC-3.1.8/tests/apc_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_002.phpt ^ |
(renamed from APC-3.1.8/tests/apc_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003.phpt ^ |
(renamed from APC-3.1.8/tests/apc_003.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003.phpt ^ |
(renamed from APC-3.1.8/tests/apc_003.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003b.phpt ^ |
(renamed from APC-3.1.8/tests/apc_003b.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_003b.phpt ^ |
(renamed from APC-3.1.8/tests/apc_003b.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_004.phpt ^ |
(renamed from APC-3.1.8/tests/apc_004.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_004.phpt ^ |
(renamed from APC-3.1.8/tests/apc_004.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_005.phpt ^ |
(renamed from APC-3.1.8/tests/apc_005.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_005.phpt ^ |
(renamed from APC-3.1.8/tests/apc_005.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_006.phpt ^ |
(renamed from APC-3.1.8/tests/apc_006.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_006.phpt ^ |
(renamed from APC-3.1.8/tests/apc_006.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_007.phpt ^ |
(renamed from APC-3.1.8/tests/apc_007.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_007.phpt ^ |
(renamed from APC-3.1.8/tests/apc_007.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_008.phpt ^ |
(renamed from APC-3.1.8/tests/apc_008.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_008.phpt ^ |
(renamed from APC-3.1.8/tests/apc_008.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_009.phpt ^ |
(renamed from APC-3.1.8/tests/apc_009.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_009.phpt ^ |
(renamed from APC-3.1.8/tests/apc_009.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_010.phpt ^ |
(renamed from APC-3.1.8/tests/apc_010.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_010.phpt ^ |
(renamed from APC-3.1.8/tests/apc_010.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_001.phpt ^ |
(renamed from APC-3.1.8/tests/apc_bin_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_001.phpt ^ |
(renamed from APC-3.1.8/tests/apc_bin_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-1.inc ^ |
(renamed from APC-3.1.8/tests/apc_bin_002-1.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-1.inc ^ |
(renamed from APC-3.1.8/tests/apc_bin_002-1.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-2.inc ^ |
(renamed from APC-3.1.8/tests/apc_bin_002-2.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002-2.inc ^ |
(renamed from APC-3.1.8/tests/apc_bin_002-2.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002.phpt ^ |
(renamed from APC-3.1.8/tests/apc_bin_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/apc_bin_002.phpt ^ |
(renamed from APC-3.1.8/tests/apc_bin_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_001.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_001.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_001.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_002.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_002.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_002.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_003.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_003.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_003.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_003.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_004.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_004.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_004.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_004.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_005.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_005.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_005.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_005.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_006.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_006.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_006.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_006.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_007.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_007.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/iterator_007.phpt ^ |
(renamed from APC-3.1.8/tests/iterator_007.phpt) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/php_5_3_ns.inc ^ |
(renamed from APC-3.1.8/tests/php_5_3_ns.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/php_5_3_ns.inc ^ |
(renamed from APC-3.1.8/tests/php_5_3_ns.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/skipif.inc ^ |
(renamed from APC-3.1.8/tests/skipif.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/APC-3.1.9/tests/skipif.inc ^ |
(renamed from APC-3.1.8/tests/skipif.inc) | ||
[+] | Changed | APC-3.1.9.tar.bz2/package.xml ^ |
@@ -70,10 +70,10 @@ <email>pierre@php.net</email> <active>yes</active> </developer> - <date>2011-05-03</date> - <time>00:03:03</time> + <date>2011-05-14</date> + <time>22:14:56</time> <version> - <release>3.1.8</release> + <release>3.1.9</release> <api>3.1.0</api> </version> <stability> @@ -82,13 +82,7 @@ </stability> <license uri="http://www.php.net/license">PHP License</license> <notes> -- Windows read-write locks support on Windows XP or later and Windows Win7 - or later (use php_apc-xp.dll or php_apc-win7.dll) -- Fix variable type check in user cache update -- Make warnings that user cannot do anything about debug messages -- Fixed bug #21400 (Minor memory leak in MINFO) -- Fixed bug #18890: Ensure that --enable-apc-debug=no disables debug mode. -- Fixed bug #19459: check for expiry while looping through the iterator slots +- Fix regression introduced in 3.1.8 (#22687) </notes> <contents> <dir name="/"> @@ -131,7 +125,7 @@ <file md5sum="42a72f3101326949f86209dec05444e3" name="apc.h" role="src" /> <file md5sum="596a95143feb4d53c5dd6d77fa4cc2c4" name="apc_bin.c" role="src" /> <file md5sum="2a471d33e6073a488c58423c4afa9118" name="apc_bin.h" role="src" /> - <file md5sum="cd387b684c0f03b09a9e7c0b7085b534" name="apc_cache.c" role="src" /> + <file md5sum="91eb8777c494ff85b0a655720d894d49" name="apc_cache.c" role="src" /> <file md5sum="67ab3e67b85e41b3ba2c22798e1f097e" name="apc_cache.h" role="src" /> <file md5sum="260bac1697f30ee2256c582b233648c6" name="apc_compile.c" role="src" /> <file md5sum="a75411f0dc7cde9257839ad688d59d72" name="apc_compile.h" role="src" /> @@ -141,7 +135,7 @@ <file md5sum="fc1133b9f93f8d756146aff47e02644c" name="apc_fcntl.h" role="src" /> <file md5sum="dfb1941a4e6782d08e72f6273032e467" name="apc_globals.h" role="src" /> <file md5sum="559af28331f80c051a7c757f897284a8" name="apc_lock.h" role="src" /> - <file md5sum="7d798e83f2bef2e1759035f79a167d78" name="apc_main.c" role="src" /> + <file md5sum="afd6de81f908eba39cac5befd539a578" name="apc_main.c" role="src" /> <file md5sum="fbe1d110e5c3e53144617291d279705f" name="apc_main.h" role="src" /> <file md5sum="7a8be65b98fb812e88d3e58b81787ef6" name="apc_mmap.c" role="src" /> <file md5sum="e6ce0f97275d5b248427c43b5e57612b" name="apc_mmap.h" role="src" /> @@ -176,7 +170,7 @@ <file md5sum="4cbe31c6d02a132e2bd39295b60bd76b" name="config.m4" role="src" /> <file md5sum="ce19b60cb46446fd14a1e7bd610affab" name="config.w32" role="src" /> <file md5sum="36ecc3629dea331619d0567a9fa46d5a" name="php_apc.c" role="src" /> - <file md5sum="2a7a1ac773a86e633ea16b88857c3c58" name="php_apc.h" role="src" /> + <file md5sum="05ee2b43d64b97cf0cfc070ecc352d71" name="php_apc.h" role="src" /> <file md5sum="c0df9bd11d18a5b45a5e45458702def4" name="pgsql_s_lock.c" role="src" /> <file md5sum="b60f9504f82c958966c885fadc97fd15" name="pgsql_s_lock.h" role="src" /> <file md5sum="bbc2c54389717c4519befa7fbd68f5f2" name="apc_fcntl_win32.c" role="src" /> @@ -206,6 +200,27 @@ </extsrcrelease> <changelog> <release> + <date>2011-05-03</date> + <version> + <release>3.1.8</release> + <api>3.1.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.php.net/license">PHP License</license> + <notes> +- Windows read-write locks support on Windows XP or later and Windows Win7 + or later (use php_apc-xp.dll or php_apc-win7.dll) +- Fix variable type check in user cache update +- Make warnings that user cannot do anything about debug messages +- Fixed bug #21400 (Minor memory leak in MINFO) +- Fixed bug #18890: Ensure that --enable-apc-debug=no disables debug mode. +- Fixed bug #19459: check for expiry while looping through the iterator slots + </notes> + </release> + <release> <date>2011-01-11</date> <version> <release>3.1.7</release> |