X-Git-Url: http://git.archive.openwrt.org/?a=blobdiff_plain;f=lang%2Fphp5%2Fpatches%2F005-APC.patch;h=b6c5e3b81a721bbe374b4f297c9ec769b16bb517;hb=220fb0aa58957215c8952c4b53e7dbfa4986cc47;hp=98b5bf71127ed90a9baf7a6e4d66570f4ba01b5f;hpb=90c8b53715f023ebc3d76cd34c2113ff43e1d537;p=packages.git diff --git a/lang/php5/patches/005-APC.patch b/lang/php5/patches/005-APC.patch index 98b5bf711..b6c5e3b81 100644 --- a/lang/php5/patches/005-APC.patch +++ b/lang/php5/patches/005-APC.patch @@ -1,553 +1,1052 @@ -Index: php-5.2.3/ext/apc/apc.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,554 @@ +diff -Naur a/ext/apc/apc_bin.c b/ext/apc/apc_bin.c +--- a/ext/apc/apc_bin.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_bin.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,987 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | ++ | 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 | -+ | George Schlossnagle | -+ | Rasmus Lerdorf | -+ | Arun C. Murthy | -+ | Gopal Vijayaraghavan | ++ | Authors: Brian Shire | + +----------------------------------------------------------------------+ + -+ 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_bin.c 324017 2012-03-08 09:46:22Z pajoye $ */ + ++/* Creates a binary architecture specific output to a string or file containing ++ * the current cache contents for both fies and user variables. This is accomplished ++ * via the apc_copy_* functions and "swizzling" pointer values to a position ++ * independent value, and unswizzling them on restoration. + */ + -+/* $Id: apc.c,v 3.17 2007/03/17 14:01:41 gopalv Exp $ */ ++#include "apc_globals.h" ++#include "apc_bin.h" ++#include "apc_zend.h" ++#include "apc_php.h" ++#include "apc_sma.h" ++#include "apc_pool.h" ++#include "ext/standard/md5.h" ++#include "ext/standard/crc32.h" + -+#include "apc.h" -+#include /* for POSIX regular expressions */ -+#include "php.h" ++extern apc_cache_t* apc_cache; ++extern apc_cache_t* apc_user_cache; + -+#define NELEMS(a) (sizeof(a)/sizeof((a)[0])) ++extern int _apc_store(char *strkey, int strkey_len, const zval *val, const uint ttl, const int exclusive TSRMLS_DC); /* this is hacky */ + -+/* {{{ memory allocation wrappers */ ++#define APC_BINDUMP_DEBUG 0 + -+void* apc_emalloc(size_t n) -+{ -+ void* p = malloc(n); -+ if (p == NULL) { -+ apc_eprint("apc_emalloc: malloc failed to allocate %u bytes:", n); -+ } -+ return p; -+} + -+void* apc_erealloc(void* p, size_t n) -+{ -+ p = realloc(p, n); -+ if (p == NULL) { -+ apc_eprint("apc_erealloc: realloc failed to allocate %u bytes:", n); -+ } -+ return p; -+} ++#if APC_BINDUMP_DEBUG + -+void apc_efree(void* p) -+{ -+ if (p == NULL) { -+ apc_eprint("apc_efree: attempt to free null pointer"); -+ } -+ free(p); -+} ++#define SWIZZLE(bd, ptr) \ ++ do { \ ++ if((long)bd < (long)ptr && (ulong)ptr < ((long)bd + bd->size)) { \ ++ printf("SWIZZLE: %x ~> ", ptr); \ ++ ptr = (void*)((long)(ptr) - (long)(bd)); \ ++ printf("%x in %s on line %d", ptr, __FILE__, __LINE__); \ ++ } else if((long)ptr > bd->size) { /* not swizzled */ \ ++ apc_error("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d" TSRMLS_CC, (long)bd, ptr, ((long)bd + bd->size), __FILE__, __LINE__); \ ++ return; \ ++ } \ ++ printf("\n"); \ ++ } while(0); + -+char* apc_estrdup(const char* s) -+{ -+ int len; -+ char* dup; ++#define UNSWIZZLE(bd, ptr) \ ++ do { \ ++ printf("UNSWIZZLE: %x -> ", ptr); \ ++ ptr = (void*)((long)(ptr) + (long)(bd)); \ ++ printf("%x in %s on line %d \n", ptr, __FILE__, __LINE__); \ ++ } while(0); + -+ if (s == NULL) { -+ return NULL; -+ } -+ len = strlen(s); -+ dup = (char*) malloc(len+1); -+ if (dup == NULL) { -+ apc_eprint("apc_estrdup: malloc failed to allocate %u bytes:", len+1); -+ } -+ memcpy(dup, s, len); -+ dup[len] = '\0'; -+ return dup; -+} ++#else /* !APC_BINDUMP_DEBUG */ + -+void* apc_xstrdup(const char* s, apc_malloc_t f) -+{ -+ return s != NULL ? apc_xmemcpy(s, strlen(s)+1, f) : NULL; -+} ++#define SWIZZLE(bd, ptr) \ ++ do { \ ++ if((long)bd < (long)ptr && (ulong)ptr < ((long)bd + bd->size)) { \ ++ ptr = (void*)((long)(ptr) - (long)(bd)); \ ++ } else if((ulong)ptr > bd->size) { /* not swizzled */ \ ++ apc_error("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d" TSRMLS_CC, (long)bd, ptr, ((long)bd + bd->size), __FILE__, __LINE__); \ ++ return NULL; \ ++ } \ ++ } while(0); + -+void* apc_xmemcpy(const void* p, size_t n, apc_malloc_t f) -+{ -+ void* q; ++#define UNSWIZZLE(bd, ptr) \ ++ do { \ ++ ptr = (void*)((long)(ptr) + (long)(bd)); \ ++ } while(0); + -+ if (p != NULL && (q = f(n)) != NULL) { -+ memcpy(q, p, n); -+ return q; -+ } -+ return NULL; -+} ++#endif + -+/* }}} */ + -+/* {{{ console display functions */ ++static void *apc_bd_alloc(size_t size TSRMLS_DC); ++static void apc_bd_free(void *ptr TSRMLS_DC); ++static void *apc_bd_alloc_ex(void *ptr_new, size_t size TSRMLS_DC); + -+static void my_log(int level, const char* fmt, va_list args) -+{ -+ static const char* level_strings[] = { -+ "apc-debug", -+ "apc-notice", -+ "apc-warning", -+ "apc-error" -+ }; -+ static const int num_levels = NELEMS(level_strings); ++typedef void (*apc_swizzle_cb_t)(apc_bd_t *bd, zend_llist *ll, void *ptr TSRMLS_DC); + -+ time_t now; -+ char* buf; /* for ctime */ ++#if APC_BINDUMP_DEBUG ++#define apc_swizzle_ptr(bd, ll, ptr) _apc_swizzle_ptr(bd, ll, (void*)ptr, __FILE__, __LINE__ TSRMLS_CC) ++#else ++#define apc_swizzle_ptr(bd, ll, ptr) _apc_swizzle_ptr(bd, ll, (void*)ptr, NULL, 0 TSRMLS_CC) ++#endif + -+ fflush(stdout); ++static void _apc_swizzle_ptr(apc_bd_t *bd, zend_llist *ll, void **ptr, const char* file, int line TSRMLS_DC); ++static void apc_swizzle_function(apc_bd_t *bd, zend_llist *ll, zend_function *func TSRMLS_DC); ++static void apc_swizzle_class_entry(apc_bd_t *bd, zend_llist *ll, zend_class_entry *ce TSRMLS_DC); ++static void apc_swizzle_hashtable(apc_bd_t *bd, zend_llist *ll, HashTable *ht, apc_swizzle_cb_t swizzle_cb, int is_ptr TSRMLS_DC); ++static void apc_swizzle_zval(apc_bd_t *bd, zend_llist *ll, zval *zv TSRMLS_DC); ++static void apc_swizzle_op_array(apc_bd_t *bd, zend_llist *ll, zend_op_array *op_array TSRMLS_DC); ++static void apc_swizzle_property_info(apc_bd_t *bd, zend_llist *ll, zend_property_info *pi TSRMLS_DC); ++static void apc_swizzle_function_entry(apc_bd_t *bd, zend_llist *ll, const zend_function_entry *fe TSRMLS_DC); ++static void apc_swizzle_arg_info_array(apc_bd_t *bd, zend_llist *ll, const zend_arg_info* arg_info_array, uint num_args TSRMLS_DC); + -+ if (level < 0) -+ level = 0; -+ else if (level >= num_levels) -+ level = num_levels-1; -+ -+ now = time(0); -+ buf = ctime(&now); /* TODO: replace with reentrant impl */ -+ buf[24] = '\0'; ++static apc_bd_t* apc_swizzle_bd(apc_bd_t* bd, zend_llist *ll TSRMLS_DC); ++static int apc_unswizzle_bd(apc_bd_t *bd, int flags TSRMLS_DC); + -+ fprintf(stderr, "[%s] [%s] ", buf, level_strings[level]); -+ vfprintf(stderr, fmt, args); + -+ if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') { -+ fprintf(stderr, " %s", strerror(errno)); -+ } -+ fprintf(stderr, "\n"); ++/* {{{ apc_bd_alloc ++ * callback for copy_* functions */ ++static void *apc_bd_alloc(size_t size TSRMLS_DC) { ++ return apc_bd_alloc_ex(NULL, size TSRMLS_CC); ++} /* }}} */ + -+ if (level == APC_ERROR) { -+ exit(2); ++ ++/* {{{ apc_bd_free ++ * callback for copy_* functions */ ++static void apc_bd_free(void *ptr TSRMLS_DC) { ++ size_t *size; ++ if(zend_hash_index_find(&APCG(apc_bd_alloc_list), (ulong)ptr, (void**)&size) == FAILURE) { ++ apc_error("apc_bd_free could not free pointer (not found in list: %x)" TSRMLS_CC, ptr); ++ return; + } -+} ++ APCG(apc_bd_alloc_ptr) = (void*)((size_t)APCG(apc_bd_alloc_ptr) - *size); ++ zend_hash_index_del(&APCG(apc_bd_alloc_list), (ulong)ptr); ++} /* }}} */ + -+void apc_log(int level, const char* fmt, ...) -+{ -+ va_list args; -+ va_start(args, fmt); -+ my_log(level, fmt, args); -+ va_end(args); -+} + -+void apc_eprint(const char* fmt, ...) -+{ -+ va_list args; -+ va_start(args, fmt); -+ my_log(APC_ERROR, fmt, args); -+ va_end(args); -+} ++/* {{{ apc_bd_alloc_ex ++ * set ranges or allocate a block of data from an already (e)malloc'd range. ++ * if ptr_new is not NULL, it will reset the pointer to start at ptr_new, ++ * with a range of size. If ptr_new is NULL, returns the next available ++ * block of given size. ++ */ ++static void *apc_bd_alloc_ex(void *ptr_new, size_t size TSRMLS_DC) { ++ void *rval; ++ ++ rval = APCG(apc_bd_alloc_ptr); ++ if(ptr_new != NULL) { /* reset ptrs */ ++ APCG(apc_bd_alloc_ptr) = ptr_new; ++ APCG(apc_bd_alloc_ubptr) = (void*)((unsigned char *) ptr_new + size); ++ } else { /* alloc block */ ++ APCG(apc_bd_alloc_ptr) = (void*)((size_t)APCG(apc_bd_alloc_ptr) + size); ++#if APC_BINDUMP_DEBUG ++ apc_notice("apc_bd_alloc: rval: 0x%x ptr: 0x%x ubptr: 0x%x size: %d" TSRMLS_CC, rval, APCG(apc_bd_alloc_ptr), APCG(apc_bd_alloc_ubptr), size); ++#endif ++ if(APCG(apc_bd_alloc_ptr) > APCG(apc_bd_alloc_ubptr)) { ++ apc_error("Exceeded bounds check in apc_bd_alloc_ex by %d bytes." TSRMLS_CC, (unsigned char *) APCG(apc_bd_alloc_ptr) - (unsigned char *) APCG(apc_bd_alloc_ubptr)); ++ return NULL; ++ } ++ zend_hash_index_update(&APCG(apc_bd_alloc_list), (ulong)rval, &size, sizeof(size_t), NULL); ++ } + -+void apc_wprint(const char* fmt, ...) -+{ -+ va_list args; -+ va_start(args, fmt); -+ my_log(APC_WARNING, fmt, args); -+ va_end(args); -+} ++ return rval; ++} /* }}} */ + -+void apc_nprint(const char* fmt, ...) -+{ -+ va_list args; -+ va_start(args, fmt); -+ my_log(APC_NOTICE, fmt, args); -+ va_end(args); -+} + -+void apc_dprint(const char* fmt, ...) -+{ -+#ifdef APC_DBG -+ va_list args; -+ va_start(args, fmt); -+ my_log(APC_DBG, fmt, args); -+ va_end(args); ++/* {{{ _apc_swizzle_ptr */ ++static void _apc_swizzle_ptr(apc_bd_t *bd, zend_llist *ll, void **ptr, const char* file, int line TSRMLS_DC) { ++ if(*ptr) { ++ if((long)bd < (long)*ptr && (ulong)*ptr < ((long)bd + bd->size)) { ++ zend_llist_add_element(ll, &ptr); ++#if APC_BINDUMP_DEBUG ++ printf("[%06d] apc_swizzle_ptr: %x -> %x ", zend_llist_count(ll), ptr, *ptr); ++ printf(" in %s on line %d \n", file, line); +#endif -+} ++ } else if((ulong)ptr > bd->size) { ++ apc_error("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d" TSRMLS_CC, (long)bd, *ptr, ((long)bd + bd->size), file, line); \ ++ return; ++ } ++ } ++} /* }}} */ + -+/* }}} */ + -+/* {{{ string and text manipulation */ ++/* {{{ apc_swizzle_op_array */ ++static void apc_swizzle_op_array(apc_bd_t *bd, zend_llist *ll, zend_op_array *op_array TSRMLS_DC) { ++ uint i; + -+char* apc_append(const char* s, const char* t) -+{ -+ int slen; -+ int tlen; -+ char* p; ++#ifdef ZEND_ENGINE_2 ++ apc_swizzle_arg_info_array(bd, ll, op_array->arg_info, op_array->num_args TSRMLS_CC); ++ apc_swizzle_ptr(bd, ll, &op_array->arg_info); ++#else ++ if (op_array->arg_types) { ++ apc_swizzle_ptr(bd, ll, &op_array->arg_types); ++ } ++#endif + -+ slen = strlen(s); -+ tlen = strlen(t); ++ apc_swizzle_ptr(bd, ll, &op_array->function_name); ++ apc_swizzle_ptr(bd, ll, &op_array->filename); ++ apc_swizzle_ptr(bd, ll, &op_array->refcount); + -+ p = (char*) apc_emalloc((slen + tlen + 1) * sizeof(char)); -+ memcpy(p, s, slen); -+ memcpy(p + slen, t, tlen + 1); ++ /* swizzle op_array */ ++ for(i=0; i < op_array->last; i++) { ++#ifndef ZEND_ENGINE_2_4 ++ if(op_array->opcodes[i].result.op_type == IS_CONST) { ++ apc_swizzle_zval(bd, ll, &op_array->opcodes[i].result.u.constant TSRMLS_CC); ++ } ++ if(op_array->opcodes[i].op1.op_type == IS_CONST) { ++ apc_swizzle_zval(bd, ll, &op_array->opcodes[i].op1.u.constant TSRMLS_CC); ++ } ++ if(op_array->opcodes[i].op2.op_type == IS_CONST) { ++ apc_swizzle_zval(bd, ll, &op_array->opcodes[i].op2.u.constant TSRMLS_CC); ++ } ++#endif ++ switch (op_array->opcodes[i].opcode) { ++ case ZEND_JMP: ++#ifdef ZEND_ENGINE_2_4 ++ apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op1.jmp_addr); ++#else ++ apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op1.u.jmp_addr); ++#endif ++ case ZEND_JMPZ: ++ case ZEND_JMPNZ: ++ case ZEND_JMPZ_EX: ++ case ZEND_JMPNZ_EX: ++#ifdef ZEND_ENGINE_2_4 ++ apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op2.jmp_addr); ++#else ++ apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op2.u.jmp_addr); ++#endif ++ } ++ } ++ apc_swizzle_ptr(bd, ll, &op_array->opcodes); + -+ return p; -+} ++ /* break-continue array ptr */ ++ if(op_array->brk_cont_array) { ++ apc_swizzle_ptr(bd, ll, &op_array->brk_cont_array); ++ } + -+char* apc_substr(const char* s, int start, int length) -+{ -+ char* substr; -+ int src_len = strlen(s); ++ /* static voriables */ ++ if(op_array->static_variables) { ++ apc_swizzle_hashtable(bd, ll, op_array->static_variables, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC); ++ apc_swizzle_ptr(bd, ll, &op_array->static_variables); ++ } + -+ /* bring start into range */ -+ if (start < 0) { -+ start = 0; ++#ifdef ZEND_ENGINE_2 ++ /* try-catch */ ++ if(op_array->try_catch_array) { ++ apc_swizzle_ptr(bd, ll, &op_array->try_catch_array); + } -+ else if (start >= src_len) { -+ start = src_len - 1; ++#endif ++ ++#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */ ++ /* vars */ ++ if(op_array->vars) { ++ for(i=0; (signed int) i < op_array->last_var; i++) { ++ apc_swizzle_ptr(bd, ll, &op_array->vars[i].name); ++ } ++ apc_swizzle_ptr(bd, ll, &op_array->vars); + } ++#endif + -+ /* bring length into range */ -+ if (length < 0 || src_len - start < length) { -+ length = src_len - start; ++#ifdef ZEND_ENGINE_2 ++ /* doc comment */ ++ if(op_array->doc_comment) { ++ apc_swizzle_ptr(bd, ll, &op_array->doc_comment); + } ++#endif + -+ /* create the substring */ -+ substr = apc_xmemcpy(s + start, length + 1, apc_emalloc); -+ substr[length] = '\0'; -+ return substr; -+} ++} /* }}} */ + -+char** apc_tokenize(const char* s, char delim) -+{ -+ char** tokens; /* array of tokens, NULL terminated */ -+ int size; /* size of tokens array */ -+ int n; /* index of next token in tokens array */ -+ int cur; /* current position in input string */ -+ int end; /* final legal position in input string */ -+ int next; /* position of next delimiter in input */ -+ -+ if (!s) { -+ return NULL; -+ } + -+ size = 2; -+ n = 0; -+ cur = 0; -+ end = strlen(s) - 1; -+ -+ tokens = (char**) apc_emalloc(size * sizeof(char*)); -+ tokens[n] = NULL; ++/* {{{ apc_swizzle_function */ ++static void apc_swizzle_function(apc_bd_t *bd, zend_llist *ll, zend_function *func TSRMLS_DC) { ++ apc_swizzle_op_array(bd, ll, &func->op_array TSRMLS_CC); ++#ifdef ZEND_ENGINE_2 ++ if(func->common.scope) { ++ apc_swizzle_ptr(bd, ll, &func->common.scope); ++ } ++#endif ++} /* }}} */ + -+ while (cur <= end) { -+ /* search for the next delimiter */ -+ char* p = strchr(s + cur, delim); -+ next = p ? p-s : end+1; + -+ /* resize token array if necessary */ -+ if (n == size-1) { -+ size *= 2; -+ tokens = (char**) apc_erealloc(tokens, size * sizeof(char*)); -+ } ++/* {{{ apc_swizzle_class_entry */ ++static void apc_swizzle_class_entry(apc_bd_t *bd, zend_llist *ll, zend_class_entry *ce TSRMLS_DC) { + -+ /* save the current token */ -+ tokens[n] = apc_substr(s, cur, next-cur); ++ uint i; + -+ tokens[++n] = NULL; -+ cur = next + 1; ++ if(ce->name) { ++ apc_swizzle_ptr(bd, ll, &ce->name); + } + -+ return tokens; -+} -+ -+/* }}} */ ++ if (ce->type == ZEND_USER_CLASS && ZEND_CE_DOC_COMMENT(ce)) { ++ apc_swizzle_ptr(bd, ll, &ZEND_CE_DOC_COMMENT(ce)); ++ } + -+/* {{{ filesystem functions */ ++#ifndef ZEND_ENGINE_2 ++ apc_swizzle_ptr(bd, ll, &ce->refcount); ++#endif + -+#ifdef PHP_WIN32 -+int apc_win32_stat(const char *path, struct stat *buf TSRMLS_DC) -+{ -+ char rpath[MAXPATHLEN]; -+ BY_HANDLE_FILE_INFORMATION fi; -+ HANDLE f; -+ -+ if (VCWD_STAT(path, buf)) { -+ return -1; ++ apc_swizzle_hashtable(bd, ll, &ce->function_table, (apc_swizzle_cb_t)apc_swizzle_function, 0 TSRMLS_CC); ++#ifdef ZEND_ENGINE_2_4 ++ if (ce->default_properties_table) { ++ for (i = 0; i < ce->default_properties_count; i++) { ++ if (ce->default_properties_table[i]) { ++ apc_swizzle_ptr(bd, ll, &ce->default_properties_table[i]); ++ apc_swizzle_zval(bd, ll, ce->default_properties_table[i] TSRMLS_CC); ++ } ++ } + } -+ -+ VCWD_REALPATH(path, rpath); -+ f = CreateFile(rpath, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL); -+ GetFileInformationByHandle(f, &fi); -+ buf->st_ino = (ino_t)fi.nFileIndexLow; -+ CloseHandle (f); -+ return 0; -+} ++#else ++ apc_swizzle_hashtable(bd, ll, &ce->default_properties, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC); +#endif + -+int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo) -+{ -+ char** paths; -+ char *exec_fname; -+ int exec_fname_length; -+ int found = 0; -+ int i; -+ TSRMLS_FETCH(); ++#ifdef ZEND_ENGINE_2 ++ apc_swizzle_hashtable(bd, ll, &ce->properties_info, (apc_swizzle_cb_t)apc_swizzle_property_info, 0 TSRMLS_CC); ++#endif + -+ assert(filename && fileinfo); ++#ifdef ZEND_ENGINE_2_4 ++ if (ce->default_static_members_table) { ++ for (i = 0; i < ce->default_static_members_count; i++) { ++ if (ce->default_static_members_table[i]) { ++ apc_swizzle_ptr(bd, ll, &ce->default_static_members_table[i]); ++ apc_swizzle_zval(bd, ll, ce->default_static_members_table[i] TSRMLS_CC); ++ } ++ } ++ } ++ ce->static_members_table = ce->default_static_members_table; ++#else ++ apc_swizzle_hashtable(bd, ll, &ce->default_static_members, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC); + -+ if (IS_ABSOLUTE_PATH(filename, strlen(filename)) && apc_stat(filename, &fileinfo->st_buf) == 0) { -+ strncpy(fileinfo->fullpath, filename, MAXPATHLEN); -+ return 0; ++ if(ce->static_members != &ce->default_static_members) { ++ apc_swizzle_hashtable(bd, ll, ce->static_members, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC); ++ } else { ++ apc_swizzle_ptr(bd, ll, &ce->static_members); + } ++#endif + -+ paths = apc_tokenize(path, DEFAULT_DIR_SEPARATOR); -+ if (!paths) -+ return -1; ++ apc_swizzle_hashtable(bd, ll, &ce->constants_table, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC); + -+ /* for each directory in paths, look for filename inside */ -+ for (i = 0; paths[i]; i++) { -+ snprintf(fileinfo->fullpath, sizeof(fileinfo->fullpath), "%s%c%s", paths[i], DEFAULT_SLASH, filename); -+ if (apc_stat(fileinfo->fullpath, &fileinfo->st_buf) == 0) { -+ found = 1; -+ break; ++ if(ce->type == ZEND_INTERNAL_CLASS && ZEND_CE_BUILTIN_FUNCTIONS(ce)) { ++ for(i=0; ZEND_CE_BUILTIN_FUNCTIONS(ce)[i].fname; i++) { ++ apc_swizzle_function_entry(bd, ll, &ZEND_CE_BUILTIN_FUNCTIONS(ce)[i] TSRMLS_CC); + } + } + -+ /* check in path of the calling scripts' current working directory */ -+ /* modified from main/streams/plain_wrapper.c */ -+ if(!found && zend_is_executing(TSRMLS_C)) { -+ exec_fname = zend_get_executed_filename(TSRMLS_C); -+ exec_fname_length = strlen(exec_fname); -+ while((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); -+ if((exec_fname && exec_fname[0] != '[') && exec_fname_length > 0) { -+ /* not: [no active file] or no path */ -+ memcpy(fileinfo->fullpath, exec_fname, exec_fname_length); -+ fileinfo->fullpath[exec_fname_length] = DEFAULT_SLASH; -+ strcpy(fileinfo->fullpath +exec_fname_length +1, filename); -+ /* apc_wprint("filename: %s, exec_fname: %s, fileinfo->fullpath: %s", filename, exec_fname, fileinfo->fullpath); */ -+ if (apc_stat(fileinfo->fullpath, &fileinfo->st_buf) == 0) { -+ found = 1; -+ } -+ } -+ } -+ -+ /* free the value returned by apc_tokenize */ -+ for (i = 0; paths[i]; i++) { -+ apc_efree(paths[i]); ++ apc_swizzle_ptr(bd, ll, &ce->constructor); ++ apc_swizzle_ptr(bd, ll, &ce->destructor); ++ apc_swizzle_ptr(bd, ll, &ce->clone); ++ apc_swizzle_ptr(bd, ll, &ce->__get); ++ apc_swizzle_ptr(bd, ll, &ce->__set); ++ apc_swizzle_ptr(bd, ll, &ce->__unset); ++ apc_swizzle_ptr(bd, ll, &ce->__isset); ++ apc_swizzle_ptr(bd, ll, &ce->__call); ++ apc_swizzle_ptr(bd, ll, &ce->serialize_func); ++ apc_swizzle_ptr(bd, ll, &ce->unserialize_func); ++ ++#ifdef ZEND_ENGINE_2_2 ++ apc_swizzle_ptr(bd, ll, &ce->__tostring); ++#endif ++ ++ if (ce->type == ZEND_USER_CLASS) { ++ apc_swizzle_ptr(bd, ll, &ZEND_CE_FILENAME(ce)); + } -+ apc_efree(paths); ++} /* }}} */ + -+ return found ? 0 : -1; -+} + -+/* }}} */ ++/* {{{ apc_swizzle_property_info */ ++static void apc_swizzle_property_info(apc_bd_t *bd, zend_llist *ll, zend_property_info *pi TSRMLS_DC) { ++ apc_swizzle_ptr(bd, ll, &pi->name); ++ apc_swizzle_ptr(bd, ll, &pi->doc_comment); + -+/* {{{ regular expression wrapper functions */ ++#ifdef ZEND_ENGINE_2_2 ++ apc_swizzle_ptr(bd, ll, &pi->ce); ++#endif ++} /* }}} */ + -+typedef struct { -+ regex_t *reg; -+ unsigned char type; -+} apc_regex; + -+void* apc_regex_compile_array(char* patterns[]) -+{ -+ apc_regex** regs; -+ int npat; -+ int i; -+ -+ if (!patterns) -+ return NULL; ++/* {{{ apc_swizzle_function_entry */ ++static void apc_swizzle_function_entry(apc_bd_t *bd, zend_llist *ll, const zend_function_entry *fe TSRMLS_DC) { ++ apc_swizzle_ptr(bd, ll, &fe->fname); ++ apc_swizzle_arg_info_array(bd, ll, fe->arg_info, fe->num_args TSRMLS_CC); ++ apc_swizzle_ptr(bd, ll, &fe->arg_info); ++} /* }}} */ + -+ /* count the number of patterns in patterns */ -+ for (npat = 0; patterns[npat] != NULL; npat++) {} + -+ if (npat == 0) -+ return NULL; ++/* {{{ apc_swizzle_arg_info_array */ ++static void apc_swizzle_arg_info_array(apc_bd_t *bd, zend_llist *ll, const zend_arg_info* arg_info_array, uint num_args TSRMLS_DC) { ++ if(arg_info_array) { ++ uint i; + -+ /* allocate the array of compiled expressions */ -+ regs = (apc_regex**) apc_emalloc(sizeof(apc_regex*) * (npat + 1)); -+ for (i = 0; i <= npat; i++) { -+ regs[i] = (apc_regex *) apc_emalloc(sizeof(apc_regex)); -+ regs[i]->reg = NULL; -+ regs[i]->type = APC_NEGATIVE_MATCH; ++ for(i=0; i < num_args; i++) { ++ apc_swizzle_ptr(bd, ll, &arg_info_array[i].name); ++ apc_swizzle_ptr(bd, ll, &arg_info_array[i].class_name); ++ } + } + -+ /* compile the expressions */ -+ for (i = 0; i < npat; i++) { -+ char *pattern = patterns[i]; -+ if(pattern[0]=='+') { regs[i]->type = APC_POSITIVE_MATCH; pattern = patterns[i]+sizeof(char); } -+ else if(pattern[0]=='-') { regs[i]->type = APC_NEGATIVE_MATCH; pattern = patterns[i]+sizeof(char); } ++} /* }}} */ ++ ++ ++/* {{{ apc_swizzle_hashtable */ ++static void apc_swizzle_hashtable(apc_bd_t *bd, zend_llist *ll, HashTable *ht, apc_swizzle_cb_t swizzle_cb, int is_ptr TSRMLS_DC) { ++ uint i; ++ Bucket **bp, **bp_prev; ++ ++ bp = &ht->pListHead; ++ while(*bp) { ++ bp_prev = bp; ++ bp = &(*bp)->pListNext; ++ if(is_ptr) { ++ swizzle_cb(bd, ll, *(void**)(*bp_prev)->pData TSRMLS_CC); ++ apc_swizzle_ptr(bd, ll, (*bp_prev)->pData); ++ } else { ++ swizzle_cb(bd, ll, (void**)(*bp_prev)->pData TSRMLS_CC); ++ } ++ apc_swizzle_ptr(bd, ll, &(*bp_prev)->pData); ++ if((*bp_prev)->pDataPtr) { ++ apc_swizzle_ptr(bd, ll, &(*bp_prev)->pDataPtr); ++ } ++ if((*bp_prev)->pListLast) { ++ apc_swizzle_ptr(bd, ll, &(*bp_prev)->pListLast); ++ } ++ if((*bp_prev)->pNext) { ++ apc_swizzle_ptr(bd, ll, &(*bp_prev)->pNext); ++ } ++ if((*bp_prev)->pLast) { ++ apc_swizzle_ptr(bd, ll, &(*bp_prev)->pLast); ++ } ++ apc_swizzle_ptr(bd, ll, bp_prev); ++ } ++ for(i=0; i < ht->nTableSize; i++) { ++ if(ht->arBuckets[i]) { ++ apc_swizzle_ptr(bd, ll, &ht->arBuckets[i]); ++ } ++ } ++ apc_swizzle_ptr(bd, ll, &ht->pListTail); + -+ regs[i]->reg = (regex_t*) apc_emalloc(sizeof(regex_t)); ++ apc_swizzle_ptr(bd, ll, &ht->arBuckets); ++} /* }}} */ + -+ if (regcomp(regs[i]->reg, pattern, REG_EXTENDED | REG_NOSUB) != 0) { -+ apc_wprint("apc_regex_compile_array: invalid expression '%s'", -+ pattern); + -+ apc_regex_destroy_array(regs); ++/* {{{ apc_swizzle_zval */ ++static void apc_swizzle_zval(apc_bd_t *bd, zend_llist *ll, zval *zv TSRMLS_DC) { + -+ return NULL; ++ if(APCG(copied_zvals).nTableSize) { ++ if(zend_hash_index_exists(&APCG(copied_zvals), (ulong)zv)) { ++ return; + } ++ zend_hash_index_update(&APCG(copied_zvals), (ulong)zv, (void**)&zv, sizeof(zval*), NULL); + } + -+ return (void*) regs; -+} ++ switch(zv->type & IS_CONSTANT_TYPE_MASK) { ++ case IS_NULL: ++ case IS_LONG: ++ case IS_DOUBLE: ++ case IS_BOOL: ++ case IS_RESOURCE: ++ /* nothing to do */ ++ break; ++ case IS_CONSTANT: ++ case IS_STRING: ++ apc_swizzle_ptr(bd, ll, &zv->value.str.val); ++ break; ++ case IS_ARRAY: ++ case IS_CONSTANT_ARRAY: ++ apc_swizzle_hashtable(bd, ll, zv->value.ht, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC); ++ apc_swizzle_ptr(bd, ll, &zv->value.ht); ++ break; ++ case IS_OBJECT: ++ break; ++ default: ++ assert(0); /* shouldn't happen */ ++ } ++} /* }}} */ + -+void apc_regex_destroy_array(void* p) -+{ -+ if (p != NULL) { -+ apc_regex** regs = (apc_regex**) p; -+ int i; + -+ for (i = 0; regs[i]->reg != NULL; i++) { -+ regfree(regs[i]->reg); -+ apc_efree(regs[i]->reg); -+ apc_efree(regs[i]); ++/* {{{ apc_swizzle_bd */ ++static apc_bd_t* apc_swizzle_bd(apc_bd_t* bd, zend_llist *ll TSRMLS_DC) { ++ int count, i; ++ PHP_MD5_CTX context; ++ unsigned char digest[16]; ++ register php_uint32 crc; ++ php_uint32 crcinit = 0; ++ char *crc_p; ++ void ***ptr; ++ void ***ptr_list; ++ ++ count = zend_llist_count(ll); ++ ptr_list = emalloc(count * sizeof(void**)); ++ ptr = zend_llist_get_first(ll); ++ for(i=0; i < count; i++) { ++#if APC_BINDUMP_DEBUG ++ printf("[%06d] ", i+1); ++#endif ++ SWIZZLE(bd, **ptr); /* swizzle ptr */ ++ if((long)bd < (long)*ptr && (ulong)*ptr < ((long)bd + bd->size)) { /* exclude ptrs that aren't actually included in the ptr list */ ++#if APC_BINDUMP_DEBUG ++ printf("[------] "); ++#endif ++ SWIZZLE(bd, *ptr); /* swizzle ptr list */ ++ ptr_list[i] = *ptr; + } -+ apc_efree(regs); ++ ptr = zend_llist_get_next(ll); + } -+} ++ SWIZZLE(bd, bd->entries); + -+int apc_regex_match_array(void* p, const char* input) -+{ -+ apc_regex** regs; ++ if(count > 0) { ++ bd = erealloc(bd, bd->size + (count * sizeof(void**))); ++ bd->num_swizzled_ptrs = count; ++ bd->swizzled_ptrs = (void***)((unsigned char *)bd + bd->size -2); /* extra -1 for null termination */ ++ bd->size += count * sizeof(void**); ++ memcpy(bd->swizzled_ptrs, ptr_list, count * sizeof(void**)); ++ SWIZZLE(bd, bd->swizzled_ptrs); ++ } else { ++ bd->num_swizzled_ptrs = 0; ++ bd->swizzled_ptrs = NULL; ++ } ++ ((char*)bd)[bd->size-1] = 0; /* silence null termination for zval strings */ ++ efree(ptr_list); ++ bd->swizzled = 1; ++ ++ /* Generate MD5/CRC32 checksum */ ++ for(i=0; i<16; i++) { bd->md5[i] = 0; } ++ bd->crc=0; ++ PHP_MD5Init(&context); ++ PHP_MD5Update(&context, (const unsigned char*)bd, bd->size); ++ PHP_MD5Final(digest, &context); ++ crc = crcinit^0xFFFFFFFF; ++ crc_p = (char*)bd; ++ for(i=bd->size; i--; ++crc_p) { ++ crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*crc_p)) & 0xFF ]; ++ } ++ memcpy(bd->md5, digest, 16); ++ bd->crc = crc; ++ ++ return bd; ++} /* }}} */ ++ ++ ++/* {{{ apc_unswizzle_bd */ ++static int apc_unswizzle_bd(apc_bd_t *bd, int flags TSRMLS_DC) { + int i; ++ unsigned char md5_orig[16]; ++ unsigned char digest[16]; ++ PHP_MD5_CTX context; ++ register php_uint32 crc; ++ php_uint32 crcinit = 0; ++ php_uint32 crc_orig; ++ char *crc_p; ++ ++ /* Verify the md5 or crc32 before we unswizzle */ ++ memcpy(md5_orig, bd->md5, 16); ++ for(i=0; i<16; i++) { bd->md5[i] = 0; } ++ crc_orig = bd->crc; ++ bd->crc=0; ++ if(flags & APC_BIN_VERIFY_MD5) { ++ PHP_MD5Init(&context); ++ PHP_MD5Update(&context, (const unsigned char*)bd, bd->size); ++ PHP_MD5Final(digest, &context); ++ if(memcmp(md5_orig, digest, 16)) { ++ apc_error("MD5 checksum of binary dump failed." TSRMLS_CC); ++ return -1; ++ } ++ } ++ if(flags & APC_BIN_VERIFY_CRC32) { ++ crc = crcinit^0xFFFFFFFF; ++ crc_p = (char*)bd; ++ for(i=bd->size; i--; ++crc_p) { ++ crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*crc_p)) & 0xFF ]; ++ } ++ if(crc_orig != crc) { ++ apc_error("CRC32 checksum of binary dump failed." TSRMLS_CC); ++ return -1; ++ } ++ } ++ memcpy(bd->md5, md5_orig, 16); /* add back md5 checksum */ ++ bd->crc = crc_orig; + -+ if (!p) -+ return 0; ++ UNSWIZZLE(bd, bd->entries); ++ UNSWIZZLE(bd, bd->swizzled_ptrs); ++ for(i=0; i < bd->num_swizzled_ptrs; i++) { ++ if(bd->swizzled_ptrs[i]) { ++ UNSWIZZLE(bd, bd->swizzled_ptrs[i]); ++ if(*bd->swizzled_ptrs[i] && (*bd->swizzled_ptrs[i] < (void*)bd)) { ++ UNSWIZZLE(bd, *bd->swizzled_ptrs[i]); ++ } ++ } ++ } + -+ regs = (apc_regex**) p; -+ for (i = 0; regs[i]->reg != NULL; i++) -+ if (regexec(regs[i]->reg, input, 0, NULL, 0) == 0) -+ return (int)(regs[i]->type); ++ bd->swizzled=0; + + return 0; -+} ++} /* }}} */ + -+/* }}} */ + -+/* {{{ crc32 implementation */ ++/* {{{ apc_bin_checkfilter */ ++static int apc_bin_checkfilter(HashTable *filter, const char *key, uint key_len) { ++ zval **zptr; + -+/* this table was generated by crc32gen() */ -+static unsigned int crc32tab[] = { -+ /* 0 */ 0x00000000, 0x3b83984b, 0x77073096, 0x4c84a8dd, -+ /* 4 */ 0xee0e612c, 0xd58df967, 0x990951ba, 0xa28ac9f1, -+ /* 8 */ 0x076dc419, 0x3cee5c52, 0x706af48f, 0x4be96cc4, -+ /* 12 */ 0xe963a535, 0xd2e03d7e, 0x9e6495a3, 0xa5e70de8, -+ /* 16 */ 0x0edb8832, 0x35581079, 0x79dcb8a4, 0x425f20ef, -+ /* 20 */ 0xe0d5e91e, 0xdb567155, 0x97d2d988, 0xac5141c3, -+ /* 24 */ 0x09b64c2b, 0x3235d460, 0x7eb17cbd, 0x4532e4f6, -+ /* 28 */ 0xe7b82d07, 0xdc3bb54c, 0x90bf1d91, 0xab3c85da, -+ /* 32 */ 0x1db71064, 0x2634882f, 0x6ab020f2, 0x5133b8b9, -+ /* 36 */ 0xf3b97148, 0xc83ae903, 0x84be41de, 0xbf3dd995, -+ /* 40 */ 0x1adad47d, 0x21594c36, 0x6ddde4eb, 0x565e7ca0, -+ /* 44 */ 0xf4d4b551, 0xcf572d1a, 0x83d385c7, 0xb8501d8c, -+ /* 48 */ 0x136c9856, 0x28ef001d, 0x646ba8c0, 0x5fe8308b, -+ /* 52 */ 0xfd62f97a, 0xc6e16131, 0x8a65c9ec, 0xb1e651a7, -+ /* 56 */ 0x14015c4f, 0x2f82c404, 0x63066cd9, 0x5885f492, -+ /* 60 */ 0xfa0f3d63, 0xc18ca528, 0x8d080df5, 0xb68b95be, -+ /* 64 */ 0x3b6e20c8, 0x00edb883, 0x4c69105e, 0x77ea8815, -+ /* 68 */ 0xd56041e4, 0xeee3d9af, 0xa2677172, 0x99e4e939, -+ /* 72 */ 0x3c03e4d1, 0x07807c9a, 0x4b04d447, 0x70874c0c, -+ /* 76 */ 0xd20d85fd, 0xe98e1db6, 0xa50ab56b, 0x9e892d20, -+ /* 80 */ 0x35b5a8fa, 0x0e3630b1, 0x42b2986c, 0x79310027, -+ /* 84 */ 0xdbbbc9d6, 0xe038519d, 0xacbcf940, 0x973f610b, -+ /* 88 */ 0x32d86ce3, 0x095bf4a8, 0x45df5c75, 0x7e5cc43e, -+ /* 92 */ 0xdcd60dcf, 0xe7559584, 0xabd13d59, 0x9052a512, -+ /* 96 */ 0x26d930ac, 0x1d5aa8e7, 0x51de003a, 0x6a5d9871, -+ /* 100 */ 0xc8d75180, 0xf354c9cb, 0xbfd06116, 0x8453f95d, -+ /* 104 */ 0x21b4f4b5, 0x1a376cfe, 0x56b3c423, 0x6d305c68, -+ /* 108 */ 0xcfba9599, 0xf4390dd2, 0xb8bda50f, 0x833e3d44, -+ /* 112 */ 0x2802b89e, 0x138120d5, 0x5f058808, 0x64861043, -+ /* 116 */ 0xc60cd9b2, 0xfd8f41f9, 0xb10be924, 0x8a88716f, -+ /* 120 */ 0x2f6f7c87, 0x14ece4cc, 0x58684c11, 0x63ebd45a, -+ /* 124 */ 0xc1611dab, 0xfae285e0, 0xb6662d3d, 0x8de5b576, -+ /* 128 */ 0x76dc4190, 0x4d5fd9db, 0x01db7106, 0x3a58e94d, -+ /* 132 */ 0x98d220bc, 0xa351b8f7, 0xefd5102a, 0xd4568861, -+ /* 136 */ 0x71b18589, 0x4a321dc2, 0x06b6b51f, 0x3d352d54, -+ /* 140 */ 0x9fbfe4a5, 0xa43c7cee, 0xe8b8d433, 0xd33b4c78, -+ /* 144 */ 0x7807c9a2, 0x438451e9, 0x0f00f934, 0x3483617f, -+ /* 148 */ 0x9609a88e, 0xad8a30c5, 0xe10e9818, 0xda8d0053, -+ /* 152 */ 0x7f6a0dbb, 0x44e995f0, 0x086d3d2d, 0x33eea566, -+ /* 156 */ 0x91646c97, 0xaae7f4dc, 0xe6635c01, 0xdde0c44a, -+ /* 160 */ 0x6b6b51f4, 0x50e8c9bf, 0x1c6c6162, 0x27eff929, -+ /* 164 */ 0x856530d8, 0xbee6a893, 0xf262004e, 0xc9e19805, -+ /* 168 */ 0x6c0695ed, 0x57850da6, 0x1b01a57b, 0x20823d30, -+ /* 172 */ 0x8208f4c1, 0xb98b6c8a, 0xf50fc457, 0xce8c5c1c, -+ /* 176 */ 0x65b0d9c6, 0x5e33418d, 0x12b7e950, 0x2934711b, -+ /* 180 */ 0x8bbeb8ea, 0xb03d20a1, 0xfcb9887c, 0xc73a1037, -+ /* 184 */ 0x62dd1ddf, 0x595e8594, 0x15da2d49, 0x2e59b502, -+ /* 188 */ 0x8cd37cf3, 0xb750e4b8, 0xfbd44c65, 0xc057d42e, -+ /* 192 */ 0x4db26158, 0x7631f913, 0x3ab551ce, 0x0136c985, -+ /* 196 */ 0xa3bc0074, 0x983f983f, 0xd4bb30e2, 0xef38a8a9, -+ /* 200 */ 0x4adfa541, 0x715c3d0a, 0x3dd895d7, 0x065b0d9c, -+ /* 204 */ 0xa4d1c46d, 0x9f525c26, 0xd3d6f4fb, 0xe8556cb0, -+ /* 208 */ 0x4369e96a, 0x78ea7121, 0x346ed9fc, 0x0fed41b7, -+ /* 212 */ 0xad678846, 0x96e4100d, 0xda60b8d0, 0xe1e3209b, -+ /* 216 */ 0x44042d73, 0x7f87b538, 0x33031de5, 0x088085ae, -+ /* 220 */ 0xaa0a4c5f, 0x9189d414, 0xdd0d7cc9, 0xe68ee482, -+ /* 224 */ 0x5005713c, 0x6b86e977, 0x270241aa, 0x1c81d9e1, -+ /* 228 */ 0xbe0b1010, 0x8588885b, 0xc90c2086, 0xf28fb8cd, -+ /* 232 */ 0x5768b525, 0x6ceb2d6e, 0x206f85b3, 0x1bec1df8, -+ /* 236 */ 0xb966d409, 0x82e54c42, 0xce61e49f, 0xf5e27cd4, -+ /* 240 */ 0x5edef90e, 0x655d6145, 0x29d9c998, 0x125a51d3, -+ /* 244 */ 0xb0d09822, 0x8b530069, 0xc7d7a8b4, 0xfc5430ff, -+ /* 248 */ 0x59b33d17, 0x6230a55c, 0x2eb40d81, 0x153795ca, -+ /* 252 */ 0xb7bd5c3b, 0x8c3ec470, 0xc0ba6cad, 0xfb39f4e6, -+}; ++ if(filter == NULL) { ++ return 1; ++ } + -+unsigned int apc_crc32(const char* buf, int len) -+{ -+ int i; -+ int k; -+ unsigned int crc; ++ if(zend_hash_find(filter, (char*)key, key_len, (void**)&zptr) == SUCCESS) { ++ if(Z_TYPE_PP(zptr) == IS_LONG && Z_LVAL_PP(zptr) == 0) { ++ return 0; ++ } ++ } else { ++ return 0; ++ } + -+ /* preconditioning */ -+ crc = 0xFFFFFFFF; -+ -+ for (i = 0; i < len; i++) { -+ k = (crc ^ buf[i]) & 0x000000FF; -+ crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[k]; ++ ++ return 1; ++} /* }}} */ ++ ++/* {{{ apc_bin_fixup_op_array */ ++static inline void apc_bin_fixup_op_array(zend_op_array *op_array) { ++ ulong i; ++ for (i = 0; i < op_array->last; i++) { ++ op_array->opcodes[i].handler = zend_opcode_handlers[APC_OPCODE_HANDLER_DECODE(&op_array->opcodes[i])]; ++ } ++} ++/* }}} */ ++ ++/* {{{ apc_bin_fixup_class_entry */ ++static inline void apc_bin_fixup_class_entry(zend_class_entry *ce) { ++ zend_function *fe; ++ HashPosition hpos; ++ ++ /* fixup the opcodes in each method */ ++ zend_hash_internal_pointer_reset_ex(&ce->function_table, &hpos); ++ while(zend_hash_get_current_data_ex(&ce->function_table, (void**)&fe, &hpos) == SUCCESS) { ++ apc_bin_fixup_op_array(&fe->op_array); ++ zend_hash_move_forward_ex(&ce->function_table, &hpos); + } + -+ /* postconditioning */ -+ return ~crc; ++ /* fixup hashtable destructor pointers */ ++ ce->function_table.pDestructor = (dtor_func_t)zend_function_dtor; ++#ifndef ZEND_ENGINE_2_4 ++ ce->default_properties.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper; ++#endif ++ ce->properties_info.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper; ++#ifndef ZEND_ENGINE_2_4 ++ ce->default_static_members.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper; ++ if (ce->static_members) { ++ ce->static_members->pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper; ++ } ++#endif ++ ce->constants_table.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper; +} ++/* }}} */ ++ ++/* {{{ apc_bin_dump */ ++apc_bd_t* apc_bin_dump(HashTable *files, HashTable *user_vars TSRMLS_DC) { + -+/* crc32gen: generate the nth (0..255) crc32 table value */ -+#if 0 -+static unsigned long crc32gen(int n) -+{ + int i; -+ unsigned long crc; -+ -+ crc = n; -+ for (i = 8; i >= 0; i--) { -+ if (crc & 1) { -+ crc = (crc >> 1) ^ 0xEDB88320; ++ uint fcount; ++ slot_t *sp; ++ apc_bd_entry_t *ep; ++ int count=0; ++ apc_bd_t *bd; ++ zend_llist ll; ++ zend_function *efp, *sfp; ++ long size=0; ++ apc_context_t ctxt; ++ void *pool_ptr; ++ ++ zend_llist_init(&ll, sizeof(void*), NULL, 0); ++ zend_hash_init(&APCG(apc_bd_alloc_list), 0, NULL, NULL, 0); ++ ++ /* flip the hash for faster filter checking */ ++ files = apc_flip_hash(files); ++ user_vars = apc_flip_hash(user_vars); ++ ++ /* get size and entry counts */ ++ for(i=0; i < apc_user_cache->num_slots; i++) { ++ sp = apc_user_cache->slots[i]; ++ for(; sp != NULL; sp = sp->next) { ++ if(apc_bin_checkfilter(user_vars, sp->key.data.user.identifier, sp->key.data.user.identifier_len)) { ++ size += sizeof(apc_bd_entry_t*) + sizeof(apc_bd_entry_t); ++ size += sp->value->mem_size - (sizeof(apc_cache_entry_t) - sizeof(apc_cache_entry_value_t)); ++ count++; ++ } + } -+ else { -+ crc >>= 1; ++ } ++ for(i=0; i < apc_cache->num_slots; i++) { ++ sp = apc_cache->slots[i]; ++ for(; sp != NULL; sp = sp->next) { ++ if(sp->key.type == APC_CACHE_KEY_FPFILE) { ++ if(apc_bin_checkfilter(files, sp->key.data.fpfile.fullpath, sp->key.data.fpfile.fullpath_len+1)) { ++ size += sizeof(apc_bd_entry_t*) + sizeof(apc_bd_entry_t); ++ size += sp->value->mem_size - (sizeof(apc_cache_entry_t) - sizeof(apc_cache_entry_value_t)); ++ count++; ++ } ++ } else { ++ /* TODO: Currently we don't support APC_CACHE_KEY_FILE type. We need to store the path and re-stat on load */ ++ apc_warning("Excluding some files from apc_bin_dump[file]. Cached files must be included using full path with apc.stat=0." TSRMLS_CC); ++ } + } + } -+ return crc; -+} ++ ++ size += sizeof(apc_bd_t) +1; /* +1 for null termination */ ++ bd = emalloc(size); ++ bd->size = size; ++ pool_ptr = emalloc(sizeof(apc_pool)); ++ apc_bd_alloc_ex(pool_ptr, sizeof(apc_pool) TSRMLS_CC); ++ ctxt.pool = apc_pool_create(APC_UNPOOL, apc_bd_alloc, apc_bd_free, NULL, NULL TSRMLS_CC); /* ideally the pool wouldn't be alloc'd as part of this */ ++ if (!ctxt.pool) { /* TODO need to cleanup */ ++ apc_warning("Unable to allocate memory for pool." TSRMLS_CC); ++ return NULL; ++ } ++ ctxt.copy = APC_COPY_IN_USER; /* avoid stupid ALLOC_ZVAL calls here, hack */ ++ apc_bd_alloc_ex((void*)((long)bd + sizeof(apc_bd_t)), bd->size - sizeof(apc_bd_t) -1 TSRMLS_CC); ++ bd->num_entries = count; ++ bd->entries = apc_bd_alloc_ex(NULL, sizeof(apc_bd_entry_t) * count TSRMLS_CC); ++ ++ /* User entries */ ++ zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0); ++ count = 0; ++ for(i=0; i < apc_user_cache->num_slots; i++) { ++ sp = apc_user_cache->slots[i]; ++ for(; sp != NULL; sp = sp->next) { ++ if(apc_bin_checkfilter(user_vars, sp->key.data.user.identifier, sp->key.data.user.identifier_len)) { ++ ep = &bd->entries[count]; ++ ep->type = sp->value->type; ++ ep->val.user.info = apc_bd_alloc(sp->value->data.user.info_len TSRMLS_CC); ++ memcpy(ep->val.user.info, sp->value->data.user.info, sp->value->data.user.info_len); ++ ep->val.user.info_len = sp->value->data.user.info_len; ++ ep->val.user.val = apc_copy_zval(NULL, sp->value->data.user.val, &ctxt TSRMLS_CC); ++ ep->val.user.ttl = sp->value->data.user.ttl; ++ ++ /* swizzle pointers */ ++ apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.user.info); ++ zend_hash_clean(&APCG(copied_zvals)); ++ apc_swizzle_zval(bd, &ll, bd->entries[count].val.user.val TSRMLS_CC); ++ apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.user.val); ++ ++ count++; ++ } ++ } ++ } ++ zend_hash_destroy(&APCG(copied_zvals)); ++ APCG(copied_zvals).nTableSize=0; ++ ++ /* File entries */ ++ for(i=0; i < apc_cache->num_slots; i++) { ++ for(sp=apc_cache->slots[i]; sp != NULL; sp = sp->next) { ++ if(sp->key.type == APC_CACHE_KEY_FPFILE) { ++ if(apc_bin_checkfilter(files, sp->key.data.fpfile.fullpath, sp->key.data.fpfile.fullpath_len+1)) { ++ ep = &bd->entries[count]; ++ ep->type = sp->key.type; ++ ep->val.file.filename = apc_bd_alloc(strlen(sp->value->data.file.filename) + 1 TSRMLS_CC); ++ strcpy(ep->val.file.filename, sp->value->data.file.filename); ++ ep->val.file.op_array = apc_copy_op_array(NULL, sp->value->data.file.op_array, &ctxt TSRMLS_CC); ++ ++ for(ep->num_functions=0; sp->value->data.file.functions[ep->num_functions].function != NULL;) { ep->num_functions++; } ++ ep->val.file.functions = apc_bd_alloc(sizeof(apc_function_t) * ep->num_functions TSRMLS_CC); ++ for(fcount=0; fcount < ep->num_functions; fcount++) { ++ memcpy(&ep->val.file.functions[fcount], &sp->value->data.file.functions[fcount], sizeof(apc_function_t)); ++ ep->val.file.functions[fcount].name = apc_xmemcpy(sp->value->data.file.functions[fcount].name, sp->value->data.file.functions[fcount].name_len+1, apc_bd_alloc TSRMLS_CC); ++ ep->val.file.functions[fcount].name_len = sp->value->data.file.functions[fcount].name_len; ++ ep->val.file.functions[fcount].function = apc_bd_alloc(sizeof(zend_function) TSRMLS_CC); ++ efp = ep->val.file.functions[fcount].function; ++ sfp = sp->value->data.file.functions[fcount].function; ++ switch(sfp->type) { ++ case ZEND_INTERNAL_FUNCTION: ++ case ZEND_OVERLOADED_FUNCTION: ++ efp->op_array = sfp->op_array; ++ break; ++ case ZEND_USER_FUNCTION: ++ case ZEND_EVAL_CODE: ++ apc_copy_op_array(&efp->op_array, &sfp->op_array, &ctxt TSRMLS_CC); ++ break; ++ default: ++ assert(0); ++ } ++#ifdef ZEND_ENGINE_2 ++ efp->common.prototype = NULL; ++ efp->common.fn_flags = sfp->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT); +#endif ++ apc_swizzle_ptr(bd, &ll, &ep->val.file.functions[fcount].name); ++ apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.functions[fcount].function); ++ apc_swizzle_op_array(bd, &ll, &efp->op_array TSRMLS_CC); ++ } + -+/* }}} */ ++ ++ for(ep->num_classes=0; sp->value->data.file.classes[ep->num_classes].class_entry != NULL;) { ep->num_classes++; } ++ ep->val.file.classes = apc_bd_alloc(sizeof(apc_class_t) * ep->num_classes TSRMLS_CC); ++ for(fcount=0; fcount < ep->num_classes; fcount++) { ++ ep->val.file.classes[fcount].name = apc_xmemcpy(sp->value->data.file.classes[fcount].name, sp->value->data.file.classes[fcount].name_len + 1, apc_bd_alloc TSRMLS_CC); ++ ep->val.file.classes[fcount].name_len = sp->value->data.file.classes[fcount].name_len; ++ ep->val.file.classes[fcount].class_entry = apc_copy_class_entry(NULL, sp->value->data.file.classes[fcount].class_entry, &ctxt TSRMLS_CC); ++ ep->val.file.classes[fcount].parent_name = apc_xstrdup(sp->value->data.file.classes[fcount].parent_name, apc_bd_alloc TSRMLS_CC); ++ ++ apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].name); ++ apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].parent_name); ++ apc_swizzle_class_entry(bd, &ll, ep->val.file.classes[fcount].class_entry TSRMLS_CC); ++ apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].class_entry); ++ } ++ ++ apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.file.filename); ++ apc_swizzle_op_array(bd, &ll, bd->entries[count].val.file.op_array TSRMLS_CC); ++ apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.file.op_array); ++ apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.functions); ++ apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.classes); ++ ++ count++; ++ } else { ++ /* TODO: Currently we don't support APC_CACHE_KEY_FILE type. We need to store the path and re-stat on load */ ++ } ++ } ++ } ++ } ++ ++ /* append swizzle pointer list to bd */ ++ bd = apc_swizzle_bd(bd, &ll TSRMLS_CC); ++ zend_llist_destroy(&ll); ++ zend_hash_destroy(&APCG(apc_bd_alloc_list)); ++ ++ if(files) { ++ zend_hash_destroy(files); ++ efree(files); ++ } ++ if(user_vars) { ++ zend_hash_destroy(user_vars); ++ efree(user_vars); ++ } ++ ++ efree(pool_ptr); ++ ++ return bd; ++} /* }}} */ ++ ++ ++/* {{{ apc_bin_load */ ++int apc_bin_load(apc_bd_t *bd, int flags TSRMLS_DC) { ++ ++ apc_bd_entry_t *ep; ++ uint i, i2; ++ int ret; ++ time_t t; ++ zend_op_array *alloc_op_array = NULL; ++ apc_function_t *alloc_functions = NULL; ++ apc_class_t *alloc_classes = NULL; ++ apc_cache_entry_t *cache_entry; ++ apc_cache_key_t cache_key; ++ apc_context_t ctxt; ++ ++ if (bd->swizzled) { ++ if(apc_unswizzle_bd(bd, flags TSRMLS_CC) < 0) { ++ return -1; ++ } ++ } ++ ++ t = apc_time(); ++ ++ for(i = 0; i < bd->num_entries; i++) { ++ ctxt.pool = apc_pool_create(APC_SMALL_POOL, apc_sma_malloc, apc_sma_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC); ++ if (!ctxt.pool) { /* TODO need to cleanup previous pools */ ++ apc_warning("Unable to allocate memory for pool." TSRMLS_CC); ++ goto failure; ++ } ++ ep = &bd->entries[i]; ++ switch (ep->type) { ++ case APC_CACHE_KEY_FILE: ++ /* TODO: Currently we don't support APC_CACHE_KEY_FILE type. We need to store the path and re-stat on load (or something else perhaps?) */ ++ break; ++ case APC_CACHE_KEY_FPFILE: ++ ctxt.copy = APC_COPY_IN_OPCODE; ++ ++ HANDLE_BLOCK_INTERRUPTIONS(); ++#if NONBLOCKING_LOCK_AVAILABLE ++ if(APCG(write_lock)) { ++ if(!apc_cache_write_lock(apc_cache TSRMLS_CC)) { ++ HANDLE_UNBLOCK_INTERRUPTIONS(); ++ return -1; ++ } ++ } ++#endif ++ if(! (alloc_op_array = apc_copy_op_array(NULL, ep->val.file.op_array, &ctxt TSRMLS_CC))) { ++ goto failure; ++ } ++ apc_bin_fixup_op_array(alloc_op_array); ++ ++ if(! (alloc_functions = apc_sma_malloc(sizeof(apc_function_t) * (ep->num_functions + 1) TSRMLS_CC))) { ++ goto failure; ++ } ++ for(i2=0; i2 < ep->num_functions; i2++) { ++ if(! (alloc_functions[i2].name = apc_xmemcpy(ep->val.file.functions[i2].name, ep->val.file.functions[i2].name_len + 1, apc_sma_malloc TSRMLS_CC))) { ++ goto failure; ++ } ++ alloc_functions[i2].name_len = ep->val.file.functions[i2].name_len; ++ if(! (alloc_functions[i2].function = apc_sma_malloc(sizeof(zend_function) TSRMLS_CC))) { ++ goto failure; ++ } ++ switch(ep->val.file.functions[i2].function->type) { ++ case ZEND_INTERNAL_FUNCTION: ++ case ZEND_OVERLOADED_FUNCTION: ++ alloc_functions[i2].function->op_array = ep->val.file.functions[i2].function->op_array; ++ break; ++ case ZEND_USER_FUNCTION: ++ case ZEND_EVAL_CODE: ++ if (!apc_copy_op_array(&alloc_functions[i2].function->op_array, &ep->val.file.functions[i2].function->op_array, &ctxt TSRMLS_CC)) { ++ goto failure; ++ } ++ apc_bin_fixup_op_array(&alloc_functions[i2].function->op_array); ++ break; ++ default: ++ assert(0); ++ } ++#ifdef ZEND_ENGINE_2 ++ alloc_functions[i2].function->common.prototype=NULL; ++ alloc_functions[i2].function->common.fn_flags=ep->val.file.functions[i2].function->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT); ++#endif ++ } ++ alloc_functions[i2].name = NULL; ++ alloc_functions[i2].function = NULL; ++ ++ if(! (alloc_classes = apc_sma_malloc(sizeof(apc_class_t) * (ep->num_classes + 1) TSRMLS_CC))) { ++ goto failure; ++ } ++ for(i2=0; i2 < ep->num_classes; i2++) { ++ if(! (alloc_classes[i2].name = apc_xmemcpy(ep->val.file.classes[i2].name, ep->val.file.classes[i2].name_len+1, apc_sma_malloc TSRMLS_CC))) { ++ goto failure; ++ } ++ alloc_classes[i2].name_len = ep->val.file.classes[i2].name_len; ++ if(! (alloc_classes[i2].class_entry = apc_copy_class_entry(NULL, ep->val.file.classes[i2].class_entry, &ctxt TSRMLS_CC))) { ++ goto failure; ++ } ++ apc_bin_fixup_class_entry(alloc_classes[i2].class_entry); ++ if(! (alloc_classes[i2].parent_name = apc_xstrdup(ep->val.file.classes[i2].parent_name, apc_sma_malloc TSRMLS_CC))) { ++ if(ep->val.file.classes[i2].parent_name != NULL) { ++ goto failure; ++ } ++ } ++ } ++ alloc_classes[i2].name = NULL; ++ alloc_classes[i2].class_entry = NULL; ++ ++ if(!(cache_entry = apc_cache_make_file_entry(ep->val.file.filename, alloc_op_array, alloc_functions, alloc_classes, &ctxt TSRMLS_CC))) { ++ goto failure; ++ } ++ ++ if (!apc_cache_make_file_key(&cache_key, ep->val.file.filename, PG(include_path), t TSRMLS_CC)) { ++ goto failure; ++ } ++ ++ if ((ret = apc_cache_insert(apc_cache, cache_key, cache_entry, &ctxt, t TSRMLS_CC)) != 1) { ++ if(ret==-1) { ++ goto failure; ++ } ++ } ++ ++#if NONBLOCKING_LOCK_AVAILABLE ++ if(APCG(write_lock)) { ++ apc_cache_write_unlock(apc_cache TSRMLS_CC); ++ } ++#endif ++ HANDLE_UNBLOCK_INTERRUPTIONS(); ++ ++ break; ++ case APC_CACHE_KEY_USER: ++ ctxt.copy = APC_COPY_IN_USER; ++ _apc_store(ep->val.user.info, ep->val.user.info_len, ep->val.user.val, ep->val.user.ttl, 0 TSRMLS_CC); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return 0; ++ ++failure: ++ apc_pool_destroy(ctxt.pool TSRMLS_CC); ++ apc_warning("Unable to allocate memory for apc binary load/dump functionality." TSRMLS_CC); ++#if NONBLOCKING_LOCK_AVAILABLE ++ if(APCG(write_lock)) { ++ apc_cache_write_unlock(apc_cache TSRMLS_CC); ++ } ++#endif ++ HANDLE_UNBLOCK_INTERRUPTIONS(); ++ return -1; ++} /* }}} */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim<600: expandtab sw=4 ts=4 sts=4 ++ */ +diff -Naur a/ext/apc/apc_bin.h b/ext/apc/apc_bin.h +--- a/ext/apc/apc_bin.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_bin.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,63 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Brian Shire | ++ +----------------------------------------------------------------------+ ++ ++ */ ++ ++/* $Id: apc_bin.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef APC_BINDUMP_H ++#define APC_BINDUMP_H ++ ++#include "apc.h" ++#include "apc_php.h" ++#include "ext/standard/basic_functions.h" ++ ++/* APC binload flags */ ++#define APC_BIN_VERIFY_MD5 1 << 0 ++#define APC_BIN_VERIFY_CRC32 1 << 1 ++ ++typedef struct _apc_bd_entry_t { ++ unsigned char type; ++ uint num_functions; ++ uint num_classes; ++ apc_cache_entry_value_t val; ++} apc_bd_entry_t; ++ ++typedef struct _apc_bd_t { ++ unsigned int size; ++ int swizzled; ++ unsigned char md5[16]; ++ php_uint32 crc; ++ unsigned int num_entries; ++ apc_bd_entry_t *entries; ++ int num_swizzled_ptrs; ++ void ***swizzled_ptrs; ++} apc_bd_t; ++ ++apc_bd_t* apc_bin_dump(HashTable *files, HashTable *user_vars TSRMLS_DC); ++int apc_bin_load(apc_bd_t *bd, int flags TSRMLS_DC); ++ ++#endif + +/* + * Local variables: @@ -557,16 +1056,15 @@ Index: php-5.2.3/ext/apc/apc.c + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_cache.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_cache.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,1328 @@ +diff -Naur a/ext/apc/apc.c b/ext/apc/apc.c +--- a/ext/apc/apc.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,670 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -577,6 +1075,7 @@ Index: php-5.2.3/ext/apc/apc_cache.c + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | ++ | George Schlossnagle | + | Rasmus Lerdorf | + | Arun C. Murthy | + | Gopal Vijayaraghavan | @@ -592,3204 +1091,2740 @@ Index: php-5.2.3/ext/apc/apc_cache.c + + */ + -+/* $Id: apc_cache.c,v 3.140 2007/04/02 22:57:10 rasmus Exp $ */ ++/* $Id: apc.c 326710 2012-07-19 20:51:04Z rasmus $ */ + ++#include "apc.h" ++#include "apc_zend.h" +#include "apc_cache.h" -+#include "apc_lock.h" -+#include "apc_sma.h" +#include "apc_globals.h" -+#include "SAPI.h" -+#include "ext/standard/php_var.h" -+#include "ext/standard/php_smart_str.h" ++#include "php.h" + -+/* TODO: rehash when load factor exceeds threshold */ ++#if HAVE_PCRE || HAVE_BUNDLED_PCRE ++/* Deal with problem present until php-5.2.2 where php_pcre.h was not installed correctly */ ++# if !HAVE_BUNDLED_PCRE && PHP_MAJOR_VERSION == 5 && (PHP_MINOR_VERSION < 2 || (PHP_MINOR_VERSION == 2 && PHP_RELEASE_VERSION < 2)) ++# include "apc_php_pcre.h" ++# else ++# include "ext/pcre/php_pcre.h" ++# endif ++# include "ext/standard/php_smart_str.h" ++#endif + -+#define CHECK(p) { if ((p) == NULL) return NULL; } ++#define NELEMS(a) (sizeof(a)/sizeof((a)[0])) + -+/* {{{ locking macros */ -+#define CREATE_LOCK(lock) apc_lck_create(NULL, 0, 1, lock) -+#define DESTROY_LOCK(c) apc_lck_destroy(c->header->lock) -+#define LOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(c->header->lock); } -+#define RDLOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(c->header->lock); } -+#define UNLOCK(c) { apc_lck_unlock(c->header->lock); HANDLE_UNBLOCK_INTERRUPTIONS(); } -+/* }}} */ -+ -+/* {{{ struct definition: slot_t */ -+typedef struct slot_t slot_t; -+struct slot_t { -+ apc_cache_key_t key; /* slot key */ -+ apc_cache_entry_t* value; /* slot value */ -+ slot_t* next; /* next slot in linked list */ -+ int num_hits; /* number of hits to this bucket */ -+ time_t creation_time; /* time slot was initialized */ -+ time_t deletion_time; /* time slot was removed from cache */ -+ time_t access_time; /* time slot was last accessed */ -+}; -+/* }}} */ -+ -+/* {{{ struct definition: header_t -+ Any values that must be shared among processes should go in here. */ -+typedef struct header_t header_t; -+struct header_t { -+ apc_lck_t lock; /* read/write lock (exclusive blocking cache lock) */ -+ apc_lck_t wrlock; /* write lock (non-blocking used to prevent cache slams) */ -+ int num_hits; /* total successful hits in cache */ -+ int num_misses; /* total unsuccessful hits in cache */ -+ int num_inserts; /* total successful inserts in cache */ -+ slot_t* deleted_list; /* linked list of to-be-deleted slots */ -+ time_t start_time; /* time the above counters were reset */ -+ int expunges; /* total number of expunges */ -+ zend_bool busy; /* Flag to tell clients when we are busy cleaning the cache */ -+ int num_entries; /* Statistic on the number of entries */ -+ size_t mem_size; /* Statistic on the memory size used by this cache */ -+}; -+/* }}} */ -+ -+/* {{{ struct definition: apc_cache_t */ -+struct apc_cache_t { -+ void* shmaddr; /* process (local) address of shared cache */ -+ header_t* header; /* cache header (stored in SHM) */ -+ slot_t** slots; /* array of cache slots (stored in SHM) */ -+ int num_slots; /* number of slots in cache */ -+ int gc_ttl; /* maximum time on GC list for a slot */ -+ int ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */ -+}; -+/* }}} */ -+ -+/* {{{ struct definition local_slot_t */ -+typedef struct local_slot_t local_slot_t; -+struct local_slot_t { -+ slot_t *original; /* the original slot in shm */ -+ int num_hits; /* number of hits */ -+ apc_cache_entry_t *value; /* shallow copy of slot->value */ -+ local_slot_t *next; /* only for dead list */ -+}; -+/* }}} */ -+/* {{{ struct definition apc_local_cache_t */ -+struct apc_local_cache_t { -+ apc_cache_t* shmcache; /* the real cache in shm */ -+ local_slot_t* slots; /* process (local) cache of objects */ -+ local_slot_t* dead_list; /* list of objects pending removal */ -+ int num_slots; /* number of slots in cache */ -+ int ttl; /* time to live */ -+ int num_hits; /* number of hits */ -+ int generation; /* every generation lives between expunges */ -+}; -+/* }}} */ -+ -+/* {{{ key_equals */ -+#define key_equals(a, b) (a.inode==b.inode && a.device==b.device) -+/* }}} */ ++/* {{{ memory allocation wrappers */ + -+/* {{{ hash */ -+static unsigned int hash(apc_cache_key_t key) ++void* apc_emalloc(size_t n TSRMLS_DC) +{ -+ return key.data.file.device + key.data.file.inode; ++ void* p = malloc(n); ++ if (p == NULL) { ++ apc_error("apc_emalloc: malloc failed to allocate %u bytes:" TSRMLS_CC, n); ++ return NULL; ++ } ++ return p; +} -+/* }}} */ + -+/* {{{ string_nhash_8 */ -+static unsigned int string_nhash_8(const char *s, size_t len) ++void* apc_erealloc(void* p, size_t n TSRMLS_DC) +{ -+ register const unsigned int *iv = (const unsigned int *)s; -+ register unsigned int h = 0; -+ register const unsigned int *e = (const unsigned int *)(s + len - (len % sizeof(unsigned int))); -+ -+ for(;iv> ((8*sizeof(unsigned int)) - 7)); ++ void *new; ++ new = realloc(p, n); ++ if (new == NULL) { ++ apc_error("apc_erealloc: realloc failed to allocate %u bytes:" TSRMLS_CC, n); ++ return NULL; + } -+ s = (const char *)iv; -+ for(len %= sizeof(unsigned int);len;len--) { -+ h += *(s++); ++ return new; ++} ++ ++void apc_efree(void* p TSRMLS_DC) ++{ ++ if (p == NULL) { ++ apc_error("apc_efree: attempt to free null pointer" TSRMLS_CC); ++ return; + } -+ h ^= (h >> 13); -+ h ^= (h >> 7); -+ return h; ++ free(p); +} -+/* }}} */ + -+/* {{{ make_slot */ -+slot_t* make_slot(apc_cache_key_t key, apc_cache_entry_t* value, slot_t* next, time_t t) ++char* APC_ALLOC apc_estrdup(const char* s TSRMLS_DC) +{ -+ slot_t* p = apc_sma_malloc(sizeof(slot_t)); -+ if (!p) return NULL; ++ int len; ++ char* dup; + -+ if(value->type == APC_CACHE_ENTRY_USER) { -+ char *identifier = (char*) apc_xstrdup(key.data.user.identifier, apc_sma_malloc); -+ if (!identifier) { -+ apc_sma_free(p); -+ return NULL; -+ } -+ key.data.user.identifier = identifier; -+ } else if(key.type == APC_CACHE_KEY_FPFILE) { -+ char *fullpath = (char*) apc_xstrdup(key.data.fpfile.fullpath, apc_sma_malloc); -+ if (!fullpath) { -+ apc_sma_free(p); -+ return NULL; -+ } -+ key.data.fpfile.fullpath = fullpath; ++ if (s == NULL) { ++ return NULL; + } -+ p->key = key; -+ p->value = value; -+ p->next = next; -+ p->num_hits = 0; -+ p->creation_time = t; -+ p->access_time = t; -+ p->deletion_time = 0; -+ return p; ++ len = strlen(s); ++ dup = (char*) malloc(len+1); ++ if (dup == NULL) { ++ apc_error("apc_estrdup: malloc failed to allocate %u bytes:" TSRMLS_CC, len+1); ++ return NULL; ++ } ++ memcpy(dup, s, len); ++ dup[len] = '\0'; ++ return dup; +} -+/* }}} */ + -+/* {{{ free_slot */ -+static void free_slot(slot_t* slot) ++void* APC_ALLOC apc_xstrdup(const char* s, apc_malloc_t f TSRMLS_DC) +{ -+ if(slot->value->type == APC_CACHE_ENTRY_USER) { -+ apc_sma_free((char *)slot->key.data.user.identifier); -+ } else if(slot->key.type == APC_CACHE_KEY_FPFILE) { -+ apc_sma_free((char *)slot->key.data.fpfile.fullpath); -+ } -+ apc_cache_free_entry(slot->value); -+ apc_sma_free(slot); ++ return s != NULL ? apc_xmemcpy(s, strlen(s)+1, f TSRMLS_CC) : NULL; +} -+/* }}} */ + -+/* {{{ remove_slot */ -+static void remove_slot(apc_cache_t* cache, slot_t** slot) ++void* APC_ALLOC apc_xmemcpy(const void* p, size_t n, apc_malloc_t f TSRMLS_DC) +{ -+ slot_t* dead = *slot; -+ *slot = (*slot)->next; ++ void* q; + -+ cache->header->mem_size -= dead->value->mem_size; -+ cache->header->num_entries--; -+ if (dead->value->ref_count <= 0) { -+ free_slot(dead); -+ } -+ else { -+ dead->next = cache->header->deleted_list; -+ dead->deletion_time = time(0); -+ cache->header->deleted_list = dead; ++ if (p != NULL && (q = f(n TSRMLS_CC)) != NULL) { ++ memcpy(q, p, n); ++ return q; + } ++ return NULL; +} ++ +/* }}} */ + -+/* {{{ process_pending_removals */ -+static void process_pending_removals(apc_cache_t* cache) -+{ -+ slot_t** slot; -+ time_t now; ++/* {{{ console display functions */ ++#ifdef ZTS ++# define APC_PRINT_FUNCTION_PARAMETER TSRMLS_C ++#else ++# define APC_PRINT_FUNCTION_PARAMETER format ++#endif + -+ /* 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). -+ */ ++#define APC_PRINT_FUNCTION(name, verbosity) \ ++ void apc_##name(const char *format TSRMLS_DC, ...) \ ++ { \ ++ va_list args; \ ++ \ ++ va_start(args, APC_PRINT_FUNCTION_PARAMETER); \ ++ php_verror(NULL, "", verbosity, format, args TSRMLS_CC); \ ++ va_end(args); \ ++ } + -+ if (!cache->header->deleted_list) -+ return; ++APC_PRINT_FUNCTION(error, E_ERROR) ++APC_PRINT_FUNCTION(warning, E_WARNING) ++APC_PRINT_FUNCTION(notice, E_NOTICE) + -+ slot = &cache->header->deleted_list; -+ now = time(0); ++#ifdef __DEBUG_APC__ ++APC_PRINT_FUNCTION(debug, E_NOTICE) ++#else ++void apc_debug(const char *format TSRMLS_DC, ...) {} ++#endif ++/* }}} */ + -+ while (*slot != NULL) { -+ int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0; ++/* {{{ string and text manipulation */ + -+ if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) { -+ slot_t* dead = *slot; ++char* apc_append(const char* s, const char* t TSRMLS_DC) ++{ ++ int slen; ++ int tlen; ++ char* p; + -+ if (dead->value->ref_count > 0) { -+ switch(dead->value->type) { -+ case APC_CACHE_ENTRY_FILE: -+ apc_log(APC_WARNING, "GC cache entry '%s' (dev=%d ino=%d) " -+ "was on gc-list for %d seconds", dead->value->data.file.filename, -+ dead->key.data.file.device, dead->key.data.file.inode, gc_sec); -+ break; -+ case APC_CACHE_ENTRY_USER: -+ apc_log(APC_WARNING, "GC cache entry '%s' " -+ "was on gc-list for %d seconds", dead->value->data.user.info, gc_sec); -+ break; -+ } -+ } -+ *slot = dead->next; -+ free_slot(dead); -+ } -+ else { -+ slot = &(*slot)->next; -+ } -+ } ++ slen = strlen(s); ++ tlen = strlen(t); ++ ++ p = (char*) apc_emalloc((slen + tlen + 1) * sizeof(char) TSRMLS_CC); ++ memcpy(p, s, slen); ++ memcpy(p + slen, t, tlen + 1); ++ ++ return p; +} -+/* }}} */ + -+/* {{{ prevent_garbage_collection */ -+static void prevent_garbage_collection(apc_cache_entry_t* entry) ++char* apc_substr(const char* s, int start, int length TSRMLS_DC) +{ -+ /* set reference counts on zend objects to an arbitrarily high value to -+ * prevent garbage collection after execution */ -+ -+ enum { BIG_VALUE = 1000 }; ++ char* substr; ++ int src_len = strlen(s); + -+ if(entry->data.file.op_array) { -+ entry->data.file.op_array->refcount[0] = BIG_VALUE; ++ /* bring start into range */ ++ if (start < 0) { ++ start = 0; + } -+ if (entry->data.file.functions) { -+ int i; -+ apc_function_t* fns = entry->data.file.functions; -+ for (i=0; fns[i].function != NULL; i++) { -+#ifdef ZEND_ENGINE_2 -+ *(fns[i].function->op_array.refcount) = BIG_VALUE; -+#else -+ fns[i].function->op_array.refcount[0] = BIG_VALUE; -+#endif -+ } ++ else if (start >= src_len) { ++ start = src_len - 1; + } -+ if (entry->data.file.classes) { -+ int i; -+ apc_class_t* classes = entry->data.file.classes; -+ for (i=0; classes[i].class_entry != NULL; i++) { -+#ifdef ZEND_ENGINE_2 -+ classes[i].class_entry->refcount = BIG_VALUE; -+#else -+ classes[i].class_entry->refcount[0] = BIG_VALUE; -+#endif -+ } ++ ++ /* bring length into range */ ++ if (length < 0 || src_len - start < length) { ++ length = src_len - start; + } ++ ++ /* create the substring */ ++ substr = apc_xmemcpy(s + start, length + 1, apc_emalloc TSRMLS_CC); ++ substr[length] = '\0'; ++ return substr; +} -+/* }}} */ + -+/* {{{ apc_cache_create */ -+apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl) ++char** apc_tokenize(const char* s, char delim TSRMLS_DC) +{ -+ apc_cache_t* cache; -+ int cache_size; -+ int num_slots; -+ int i; ++ char** tokens; /* array of tokens, NULL terminated */ ++ int size; /* size of tokens array */ ++ int n; /* index of next token in tokens array */ ++ int cur; /* current position in input string */ ++ int end; /* final legal position in input string */ ++ int next; /* position of next delimiter in input */ + -+ num_slots = size_hint > 0 ? size_hint*2 : 2000; ++ if (!s) { ++ return NULL; ++ } + -+ cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t)); -+ cache_size = sizeof(header_t) + num_slots*sizeof(slot_t*); ++ size = 2; ++ n = 0; ++ cur = 0; ++ end = strlen(s) - 1; + -+ cache->shmaddr = apc_sma_malloc(cache_size); -+ memset(cache->shmaddr, 0, cache_size); ++ tokens = (char**) apc_emalloc(size * sizeof(char*) TSRMLS_CC); ++ tokens[n] = NULL; + -+ cache->header = (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; ++ while (cur <= end) { ++ /* search for the next delimiter */ ++ char* p = strchr(s + cur, delim); ++ next = p ? p-s : end+1; + -+ cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(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 -+ for (i = 0; i < num_slots; i++) { -+ cache->slots[i] = NULL; ++ /* resize token array if necessary */ ++ if (n == size-1) { ++ size *= 2; ++ tokens = (char**) apc_erealloc(tokens, size * sizeof(char*) TSRMLS_CC); ++ } ++ ++ /* save the current token */ ++ tokens[n] = apc_substr(s, cur, next-cur TSRMLS_CC); ++ ++ tokens[++n] = NULL; ++ cur = next + 1; + } + -+ return cache; ++ return tokens; +} -+/* }}} */ + -+/* {{{ apc_cache_destroy */ -+void apc_cache_destroy(apc_cache_t* cache) -+{ -+ DESTROY_LOCK(cache); -+ apc_efree(cache); -+} +/* }}} */ + -+/* {{{ apc_cache_clear */ -+void apc_cache_clear(apc_cache_t* cache) ++ ++/* {{{ apc_win32_restat */ ++#ifdef PHP_WIN32 ++static int apc_restat(apc_fileinfo_t *fileinfo TSRMLS_DC) +{ -+ int i; ++ HANDLE hFile; ++ BY_HANDLE_FILE_INFORMATION hInfo; + -+ if(!cache) return; ++ hFile = CreateFile(fileinfo->fullpath, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL); + -+ 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; ++ if (!hFile) { ++ apc_debug("Cannot create a file HANDLE for %s\n" TSRMLS_CC, fileinfo->fullpath); ++ return -1; ++ } + -+ for (i = 0; i < cache->num_slots; i++) { -+ slot_t* p = cache->slots[i]; -+ while (p) { -+ remove_slot(cache, &p); -+ } -+ cache->slots[i] = NULL; ++ if (!GetFileInformationByHandle(hFile, &hInfo)) { ++ apc_debug("Cannot get file information from handle\n" TSRMLS_CC); ++ CloseHandle(hFile); ++ return -1; + } -+ -+ cache->header->busy = 0; -+ UNLOCK(cache); ++ ++ CloseHandle(hFile); ++ ++ fileinfo->st_buf.sb.st_dev = hInfo.dwVolumeSerialNumber; ++ fileinfo->st_buf.sb.st_ino = (((apc_ino_t)(hInfo.nFileIndexHigh) << 32) | (apc_ino_t) hInfo.nFileIndexLow); ++ ++ return 0; ++} ++#else ++static int apc_restat(apc_fileinfo_t *fileinfo TSRMLS_DC) ++{ ++ return 0; +} ++#endif +/* }}} */ + -+/* {{{ apc_cache_expunge */ -+void apc_cache_expunge(apc_cache_t* cache, time_t t) ++/* {{{ apc_search_paths */ ++/* similar to php_stream_stat_path */ ++#define APC_URL_STAT(wrapper, filename, pstatbuf) \ ++ ((wrapper)->wops->url_stat((wrapper), (filename), PHP_STREAM_URL_STAT_QUIET, (pstatbuf), NULL TSRMLS_CC)) ++ ++/* copy out to path_buf if path_for_open isn't the same as filename */ ++#define COPY_IF_CHANGED(p) \ ++ (char*) (((p) == filename) ? filename : \ ++ (strlcpy((char*)fileinfo->path_buf, (p), sizeof(fileinfo->path_buf))) \ ++ ? (fileinfo->path_buf) : NULL) ++ ++/* len checks can be skipped here because filename is NUL terminated */ ++#define IS_RELATIVE_PATH(filename, len) \ ++ ((filename) && (filename[0] == '.' && \ ++ (IS_SLASH(filename[1]) || \ ++ (filename[1] == '.' && \ ++ IS_SLASH(filename[2]))))) ++ ++/* {{{ stupid stringifcation */ ++#if DEFAULT_SLASH == '/' ++ #define DEFAULT_SLASH_STRING "/" ++#elif DEFAULT_SLASH == '\\' ++ #define DEFAULT_SLASH_STRING "\\" ++#else ++ #error "Unknown value for DEFAULT_SLASH" ++#endif ++/* }}} */ ++ ++int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo TSRMLS_DC) +{ ++ char** paths = NULL; ++ char *exec_fname; ++ int exec_fname_length; ++ int found = 0; + int i; ++ php_stream_wrapper *wrapper = NULL; ++ char *path_for_open = NULL; + -+ if(!cache) return; ++ assert(filename && fileinfo); + -+ if(!cache->ttl) { -+ /* -+ * If cache->ttl is not set, we wipe out the entire cache when -+ * we run out of space. -+ */ -+ LOCK(cache); -+ cache->header->busy = 1; -+ cache->header->expunges++; -+ for (i = 0; i < cache->num_slots; i++) { -+ slot_t* p = cache->slots[i]; -+ while (p) { -+ remove_slot(cache, &p); -+ } -+ cache->slots[i] = NULL; -+ } -+ cache->header->busy = 0; -+ 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 -+ */ ++ wrapper = php_stream_locate_url_wrapper(filename, &path_for_open, 0 TSRMLS_CC); + -+ LOCK(cache); -+ cache->header->busy = 1; -+ 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((*p)->creation_time + (*p)->value->data.user.ttl < t) { -+ remove_slot(cache, p); -+ continue; -+ } -+ } else if(cache->ttl) { -+ if((*p)->creation_time + cache->ttl < t) { -+ remove_slot(cache, p); -+ continue; -+ } -+ } -+ } else if((*p)->access_time < (t - cache->ttl)) { -+ remove_slot(cache, p); -+ continue; -+ } -+ p = &(*p)->next; -+ } -+ } -+ cache->header->busy = 0; -+ UNLOCK(cache); ++ if(!wrapper || !wrapper->wops || !wrapper->wops->url_stat) { ++ return -1; + } -+} -+/* }}} */ -+ -+/* {{{ apc_cache_insert */ -+int apc_cache_insert(apc_cache_t* cache, -+ apc_cache_key_t key, -+ apc_cache_entry_t* value, -+ time_t t) -+{ -+ slot_t** slot; + -+ if (!value) { -+ return 0; ++ if(wrapper != &php_plain_files_wrapper) { ++ if(APC_URL_STAT(wrapper, path_for_open, &fileinfo->st_buf) == 0) { ++ fileinfo->fullpath = COPY_IF_CHANGED(path_for_open); ++ return apc_restat(fileinfo TSRMLS_CC); ++ } ++ return -1; /* cannot stat */ + } + -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"Inserting [%s]\n", value->data.file.filename); -+#endif -+ -+ LOCK(cache); -+ process_pending_removals(cache); ++ if (IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) && ++ APC_URL_STAT(wrapper, path_for_open, &fileinfo->st_buf) == 0) { ++ fileinfo->fullpath = COPY_IF_CHANGED(path_for_open); ++ return apc_restat(fileinfo TSRMLS_CC); ++ } + -+ if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots]; -+ else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots]; ++ if (!IS_RELATIVE_PATH(path_for_open, strlen(path_for_open))) { ++ paths = apc_tokenize(path, DEFAULT_DIR_SEPARATOR TSRMLS_CC); ++ if (!paths) ++ return -1; + -+ 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 ((*slot)->key.mtime != key.mtime) { -+ remove_slot(cache, slot); -+ break; -+ } -+ UNLOCK(cache); -+ return 0; -+ } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { -+ remove_slot(cache, slot); -+ continue; -+ } -+ } else { /* APC_CACHE_KEY_FPFILE */ -+ if(!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); ++ /* for each directory in paths, look for filename inside */ ++ for (i = 0; paths[i]; i++) { ++ snprintf(fileinfo->path_buf, sizeof(fileinfo->path_buf), "%s%c%s", paths[i], DEFAULT_SLASH, path_for_open); ++ if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) { ++ fileinfo->fullpath = (char*) fileinfo->path_buf; ++ found = 1; + break; -+ } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { -+ remove_slot(cache, slot); -+ continue; + } + } -+ } -+ slot = &(*slot)->next; ++ /* in cli mode PHP explicitly checks the cwd, so we should as well */ ++ if(APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) { ++ snprintf(fileinfo->path_buf, sizeof(fileinfo->path_buf), ".%c%s", DEFAULT_SLASH, path_for_open); ++ if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) { ++ fileinfo->fullpath = (char*) fileinfo->path_buf; ++ found = 1; ++ } ++ } ++ } else { ++ /* read cwd and try to fake up fullpath */ ++ fileinfo->path_buf[0] = '\0'; ++ if(VCWD_GETCWD(fileinfo->path_buf, sizeof(fileinfo->path_buf))) { ++ strlcat(fileinfo->path_buf, DEFAULT_SLASH_STRING, sizeof(fileinfo->path_buf)); ++ strlcat(fileinfo->path_buf, path_for_open, sizeof(fileinfo->path_buf)); ++ if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) { ++ fileinfo->fullpath = (char*) fileinfo->path_buf; ++ return apc_restat(fileinfo TSRMLS_CC); ++ } ++ } + } + -+ if ((*slot = make_slot(key, value, *slot, t)) == NULL) { -+ UNLOCK(cache); -+ return -1; ++ /* check in path of the calling scripts' current working directory */ ++ /* modified from main/streams/plain_wrapper.c */ ++ if(!found && zend_is_executing(TSRMLS_C)) { ++ exec_fname = zend_get_executed_filename(TSRMLS_C); ++ exec_fname_length = strlen(exec_fname); ++ while((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); ++ if((exec_fname && exec_fname[0] != '[') && exec_fname_length > 0) { ++ /* not: [no active file] or no path */ ++ memcpy(fileinfo->path_buf, exec_fname, exec_fname_length); ++ fileinfo->path_buf[exec_fname_length] = DEFAULT_SLASH; ++ strlcpy(fileinfo->path_buf +exec_fname_length +1, path_for_open,sizeof(fileinfo->path_buf)-exec_fname_length-1); ++ /* apc_warning("filename: %s, exec_fname: %s, fileinfo->path_buf: %s" TSRMLS_CC, path_for_open, exec_fname, fileinfo->path_buf); */ ++ if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) { ++ fileinfo->fullpath = (char*) fileinfo->path_buf; ++ found = 1; ++ } ++ } + } -+ -+ cache->header->mem_size += value->mem_size; -+ cache->header->num_entries++; -+ cache->header->num_inserts++; -+ -+ UNLOCK(cache); -+ return 1; ++ ++ if(paths) { ++ /* free the value returned by apc_tokenize */ ++ for (i = 0; paths[i]; i++) { ++ apc_efree(paths[i] TSRMLS_CC); ++ } ++ apc_efree(paths TSRMLS_CC); ++ } ++ ++ return found ? apc_restat(fileinfo TSRMLS_CC) : -1; +} ++ +/* }}} */ + -+/* {{{ apc_cache_user_insert */ -+int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, time_t t, int exclusive TSRMLS_DC) -+{ -+ slot_t** slot; -+ size_t* mem_size_ptr = NULL; ++/* {{{ regular expression wrapper functions */ + -+ if (!value) { -+ return 0; -+ } ++#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) ++typedef struct { ++ pcre *preg; ++ pcre *nreg; ++} apc_regex; + -+ LOCK(cache); -+ process_pending_removals(cache); ++#define APC_ADD_PATTERN(match, pat) do {\ ++ if(match.len > 1) {\ ++ smart_str_appendc(&match, '|');\ ++ }\ ++ smart_str_appendc(&match, '(');\ ++ while(*pat) {\ ++ if(*pat == '/') smart_str_appendc(&match, '\\');\ ++ \ ++ smart_str_appendc(&match, *(pat++));\ ++ }\ ++ smart_str_appendc(&match, ')');\ ++} while(0) ++ ++#define APC_COMPILE_PATTERN(re, match) do {\ ++ if(match.len > 2) { /* more than just "//" */\ ++ if (((re) = pcre_get_compiled_regex(match.c, NULL, NULL TSRMLS_CC)) == NULL) {\ ++ apc_warning("apc_regex_compile_array: invalid expression '%s'" TSRMLS_CC, match.c); \ ++ smart_str_free(&match);\ ++ return NULL;\ ++ }\ ++ } else { \ ++ (re) = NULL;\ ++ }\ ++} while(0) ++ ++void* apc_regex_compile_array(char* patterns[] TSRMLS_DC) ++{ ++ apc_regex* regs; ++ int npat; ++ smart_str pmatch = {0,}; ++ smart_str nmatch = {0,}; ++ char* pattern; + -+ slot = &cache->slots[string_nhash_8(key.data.user.identifier, key.data.user.identifier_len) % cache->num_slots]; ++ if (!patterns) ++ return NULL; + -+ if (APCG(mem_size_ptr) != NULL) { -+ mem_size_ptr = APCG(mem_size_ptr); -+ APCG(mem_size_ptr) = NULL; -+ } ++ regs = (apc_regex*) apc_emalloc(sizeof(apc_regex) TSRMLS_CC); + -+ while (*slot) { -+ if (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, key.data.user.identifier_len)) { -+ /* -+ * 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 && ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t ) -+ ) ) { -+ UNLOCK(cache); -+ return 0; -+ } -+ remove_slot(cache, slot); -+ 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 && ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) { -+ remove_slot(cache, slot); -+ continue; ++ smart_str_appendc(&pmatch, '/'); ++ smart_str_appendc(&nmatch, '/'); ++ ++ for (npat = 0; patterns[npat] != NULL; npat++) { ++ pattern = patterns[npat]; ++ if(pattern[0] == '+') { ++ pattern += sizeof(char); ++ APC_ADD_PATTERN(pmatch, pattern); ++ } else { ++ if(pattern[0] == '-') pattern += sizeof(char); ++ APC_ADD_PATTERN(nmatch, pattern); + } -+ slot = &(*slot)->next; + } ++ smart_str_appendc(&pmatch, '/'); ++ smart_str_appendc(&nmatch, '/'); + -+ if (mem_size_ptr != NULL) { -+ APCG(mem_size_ptr) = mem_size_ptr; -+ } ++ smart_str_0(&nmatch); ++ smart_str_0(&pmatch); + -+ if ((*slot = make_slot(key, value, *slot, t)) == NULL) { -+ UNLOCK(cache); -+ return 0; -+ } -+ if (APCG(mem_size_ptr) != NULL) { -+ value->mem_size = *APCG(mem_size_ptr); -+ cache->header->mem_size += *APCG(mem_size_ptr); -+ } -+ cache->header->num_entries++; -+ cache->header->num_inserts++; ++ APC_COMPILE_PATTERN(regs->preg, pmatch); ++ APC_COMPILE_PATTERN(regs->nreg, nmatch); + -+ UNLOCK(cache); -+ return 1; ++ smart_str_free(&pmatch); ++ smart_str_free(&nmatch); ++ ++ return (void*) regs; +} -+/* }}} */ + -+/* {{{ apc_cache_find_slot */ -+slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t) ++void apc_regex_destroy_array(void* p TSRMLS_DC) +{ -+ slot_t** slot; -+ volatile slot_t* retval = NULL; -+ -+ LOCK(cache); -+ if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots]; -+ else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % 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) { -+ remove_slot(cache, slot); -+ cache->header->num_misses++; -+ UNLOCK(cache); -+ return NULL; -+ } -+ (*slot)->num_hits++; -+ (*slot)->value->ref_count++; -+ (*slot)->access_time = t; -+ prevent_garbage_collection((*slot)->value); -+ cache->header->num_hits++; -+ retval = *slot; -+ UNLOCK(cache); -+ return (slot_t*)retval; -+ } -+ } else { /* APC_CACHE_KEY_FPFILE */ -+ if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { -+ /* TTL Check ? */ -+ (*slot)->num_hits++; -+ (*slot)->value->ref_count++; -+ (*slot)->access_time = t; -+ prevent_garbage_collection((*slot)->value); -+ cache->header->num_hits++; -+ retval = *slot; -+ UNLOCK(cache); -+ return (slot_t*)retval; -+ } -+ } -+ } -+ slot = &(*slot)->next; ++ if (p != NULL) { ++ apc_regex* regs = (apc_regex*) p; ++ apc_efree(regs TSRMLS_CC); + } -+ cache->header->num_misses++; -+ UNLOCK(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) -+{ -+ slot_t * slot = apc_cache_find_slot(cache, key, t); -+ return (slot) ? slot->value : NULL; -+} -+/* }}} */ ++#define APC_MATCH_PATTERN(re, input, output) do {\ ++ if (re && pcre_exec(re, NULL, (input), strlen(input), 0, 0, NULL, 0) >= 0) {\ ++ return (output);\ ++ }\ ++} while(0) + -+/* {{{ apc_cache_user_find */ -+apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t) ++ ++int apc_regex_match_array(void* p, const char* input) +{ -+ slot_t** slot; -+ volatile apc_cache_entry_t* value = NULL; ++ apc_regex* regs; + -+ LOCK(cache); ++ if (!p) ++ return 0; + -+ slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots]; ++ regs = (apc_regex*) p; + -+ while (*slot) { -+ if (!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 && ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) { -+ remove_slot(cache, slot); -+ UNLOCK(cache); -+ return NULL; -+ } -+ /* Otherwise we are fine, increase counters and return the cache entry */ -+ (*slot)->num_hits++; -+ (*slot)->value->ref_count++; -+ (*slot)->access_time = t; ++ APC_MATCH_PATTERN(regs->preg, input, APC_POSITIVE_MATCH); ++ APC_MATCH_PATTERN(regs->nreg, input, APC_NEGATIVE_MATCH); + -+ cache->header->num_hits++; -+ value = (*slot)->value; -+ UNLOCK(cache); -+ return (apc_cache_entry_t*)value; -+ } -+ slot = &(*slot)->next; ++ return 0; ++} ++#else /* no pcre */ ++void* apc_regex_compile_array(char* patterns[] TSRMLS_DC) ++{ ++ if(patterns && patterns[0] != NULL) { ++ apc_warning("pcre missing, disabling filters" TSRMLS_CC); + } -+ -+ UNLOCK(cache); + return NULL; +} -+/* }}} */ -+ -+/* {{{ apc_cache_user_delete */ -+int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen) ++void apc_regex_destroy_array(void* p) ++{ ++ /* nothing */ ++} ++int apc_regex_match_array(void* p, const char* input) +{ -+ slot_t** slot; -+ -+ LOCK(cache); -+ -+ slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots]; -+ -+ while (*slot) { -+ if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) { -+ remove_slot(cache, slot); -+ UNLOCK(cache); -+ return 1; -+ } -+ slot = &(*slot)->next; -+ } -+ -+ UNLOCK(cache); + return 0; +} ++#endif +/* }}} */ + -+/* {{{ apc_cache_release */ -+void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry) ++/* {{{ crc32 implementation */ ++ ++/* this table was generated by crc32gen() */ ++static unsigned int crc32tab[] = { ++ /* 0 */ 0x00000000, 0x3b83984b, 0x77073096, 0x4c84a8dd, ++ /* 4 */ 0xee0e612c, 0xd58df967, 0x990951ba, 0xa28ac9f1, ++ /* 8 */ 0x076dc419, 0x3cee5c52, 0x706af48f, 0x4be96cc4, ++ /* 12 */ 0xe963a535, 0xd2e03d7e, 0x9e6495a3, 0xa5e70de8, ++ /* 16 */ 0x0edb8832, 0x35581079, 0x79dcb8a4, 0x425f20ef, ++ /* 20 */ 0xe0d5e91e, 0xdb567155, 0x97d2d988, 0xac5141c3, ++ /* 24 */ 0x09b64c2b, 0x3235d460, 0x7eb17cbd, 0x4532e4f6, ++ /* 28 */ 0xe7b82d07, 0xdc3bb54c, 0x90bf1d91, 0xab3c85da, ++ /* 32 */ 0x1db71064, 0x2634882f, 0x6ab020f2, 0x5133b8b9, ++ /* 36 */ 0xf3b97148, 0xc83ae903, 0x84be41de, 0xbf3dd995, ++ /* 40 */ 0x1adad47d, 0x21594c36, 0x6ddde4eb, 0x565e7ca0, ++ /* 44 */ 0xf4d4b551, 0xcf572d1a, 0x83d385c7, 0xb8501d8c, ++ /* 48 */ 0x136c9856, 0x28ef001d, 0x646ba8c0, 0x5fe8308b, ++ /* 52 */ 0xfd62f97a, 0xc6e16131, 0x8a65c9ec, 0xb1e651a7, ++ /* 56 */ 0x14015c4f, 0x2f82c404, 0x63066cd9, 0x5885f492, ++ /* 60 */ 0xfa0f3d63, 0xc18ca528, 0x8d080df5, 0xb68b95be, ++ /* 64 */ 0x3b6e20c8, 0x00edb883, 0x4c69105e, 0x77ea8815, ++ /* 68 */ 0xd56041e4, 0xeee3d9af, 0xa2677172, 0x99e4e939, ++ /* 72 */ 0x3c03e4d1, 0x07807c9a, 0x4b04d447, 0x70874c0c, ++ /* 76 */ 0xd20d85fd, 0xe98e1db6, 0xa50ab56b, 0x9e892d20, ++ /* 80 */ 0x35b5a8fa, 0x0e3630b1, 0x42b2986c, 0x79310027, ++ /* 84 */ 0xdbbbc9d6, 0xe038519d, 0xacbcf940, 0x973f610b, ++ /* 88 */ 0x32d86ce3, 0x095bf4a8, 0x45df5c75, 0x7e5cc43e, ++ /* 92 */ 0xdcd60dcf, 0xe7559584, 0xabd13d59, 0x9052a512, ++ /* 96 */ 0x26d930ac, 0x1d5aa8e7, 0x51de003a, 0x6a5d9871, ++ /* 100 */ 0xc8d75180, 0xf354c9cb, 0xbfd06116, 0x8453f95d, ++ /* 104 */ 0x21b4f4b5, 0x1a376cfe, 0x56b3c423, 0x6d305c68, ++ /* 108 */ 0xcfba9599, 0xf4390dd2, 0xb8bda50f, 0x833e3d44, ++ /* 112 */ 0x2802b89e, 0x138120d5, 0x5f058808, 0x64861043, ++ /* 116 */ 0xc60cd9b2, 0xfd8f41f9, 0xb10be924, 0x8a88716f, ++ /* 120 */ 0x2f6f7c87, 0x14ece4cc, 0x58684c11, 0x63ebd45a, ++ /* 124 */ 0xc1611dab, 0xfae285e0, 0xb6662d3d, 0x8de5b576, ++ /* 128 */ 0x76dc4190, 0x4d5fd9db, 0x01db7106, 0x3a58e94d, ++ /* 132 */ 0x98d220bc, 0xa351b8f7, 0xefd5102a, 0xd4568861, ++ /* 136 */ 0x71b18589, 0x4a321dc2, 0x06b6b51f, 0x3d352d54, ++ /* 140 */ 0x9fbfe4a5, 0xa43c7cee, 0xe8b8d433, 0xd33b4c78, ++ /* 144 */ 0x7807c9a2, 0x438451e9, 0x0f00f934, 0x3483617f, ++ /* 148 */ 0x9609a88e, 0xad8a30c5, 0xe10e9818, 0xda8d0053, ++ /* 152 */ 0x7f6a0dbb, 0x44e995f0, 0x086d3d2d, 0x33eea566, ++ /* 156 */ 0x91646c97, 0xaae7f4dc, 0xe6635c01, 0xdde0c44a, ++ /* 160 */ 0x6b6b51f4, 0x50e8c9bf, 0x1c6c6162, 0x27eff929, ++ /* 164 */ 0x856530d8, 0xbee6a893, 0xf262004e, 0xc9e19805, ++ /* 168 */ 0x6c0695ed, 0x57850da6, 0x1b01a57b, 0x20823d30, ++ /* 172 */ 0x8208f4c1, 0xb98b6c8a, 0xf50fc457, 0xce8c5c1c, ++ /* 176 */ 0x65b0d9c6, 0x5e33418d, 0x12b7e950, 0x2934711b, ++ /* 180 */ 0x8bbeb8ea, 0xb03d20a1, 0xfcb9887c, 0xc73a1037, ++ /* 184 */ 0x62dd1ddf, 0x595e8594, 0x15da2d49, 0x2e59b502, ++ /* 188 */ 0x8cd37cf3, 0xb750e4b8, 0xfbd44c65, 0xc057d42e, ++ /* 192 */ 0x4db26158, 0x7631f913, 0x3ab551ce, 0x0136c985, ++ /* 196 */ 0xa3bc0074, 0x983f983f, 0xd4bb30e2, 0xef38a8a9, ++ /* 200 */ 0x4adfa541, 0x715c3d0a, 0x3dd895d7, 0x065b0d9c, ++ /* 204 */ 0xa4d1c46d, 0x9f525c26, 0xd3d6f4fb, 0xe8556cb0, ++ /* 208 */ 0x4369e96a, 0x78ea7121, 0x346ed9fc, 0x0fed41b7, ++ /* 212 */ 0xad678846, 0x96e4100d, 0xda60b8d0, 0xe1e3209b, ++ /* 216 */ 0x44042d73, 0x7f87b538, 0x33031de5, 0x088085ae, ++ /* 220 */ 0xaa0a4c5f, 0x9189d414, 0xdd0d7cc9, 0xe68ee482, ++ /* 224 */ 0x5005713c, 0x6b86e977, 0x270241aa, 0x1c81d9e1, ++ /* 228 */ 0xbe0b1010, 0x8588885b, 0xc90c2086, 0xf28fb8cd, ++ /* 232 */ 0x5768b525, 0x6ceb2d6e, 0x206f85b3, 0x1bec1df8, ++ /* 236 */ 0xb966d409, 0x82e54c42, 0xce61e49f, 0xf5e27cd4, ++ /* 240 */ 0x5edef90e, 0x655d6145, 0x29d9c998, 0x125a51d3, ++ /* 244 */ 0xb0d09822, 0x8b530069, 0xc7d7a8b4, 0xfc5430ff, ++ /* 248 */ 0x59b33d17, 0x6230a55c, 0x2eb40d81, 0x153795ca, ++ /* 252 */ 0xb7bd5c3b, 0x8c3ec470, 0xc0ba6cad, 0xfb39f4e6, ++}; ++ ++unsigned int apc_crc32(const char* buf, int len) +{ -+ /* local cache refcount-- is done in apc_local_cache_cleanup */ -+ if(entry->local) return; ++ int i; ++ int k; ++ unsigned int crc; ++ ++ /* preconditioning */ ++ crc = 0xFFFFFFFF; ++ ++ for (i = 0; i < len; i++) { ++ k = (crc ^ buf[i]) & 0x000000FF; ++ crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[k]; ++ } + -+ LOCK(cache); -+ entry->ref_count--; -+ UNLOCK(cache); ++ /* postconditioning */ ++ return ~crc; +} -+/* }}} */ + -+/* {{{ 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) ++/* crc32gen: generate the nth (0..255) crc32 table value */ ++#if 0 ++static unsigned long crc32gen(int n) +{ -+ static char canon_path[MAXPATHLEN]; -+ struct stat *tmp_buf=NULL; -+ struct apc_fileinfo_t fileinfo = { {0}, }; -+ int len; -+ -+ assert(key != NULL); -+ -+ if (!filename || !SG(request_info).path_translated) { -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"No filename and no path_translated - bailing\n"); -+#endif -+ return 0; -+ } ++ int i; ++ unsigned long crc; + -+ 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->mtime = t; -+ key->type = APC_CACHE_KEY_FPFILE; -+ } else { -+ if(!realpath(filename, canon_path)) { -+ fprintf(stderr, "realpath failed to canonicalize %s - bailing\n", filename); -+ return 0; -+ } -+ key->data.fpfile.fullpath = canon_path; -+ key->data.fpfile.fullpath_len = strlen(canon_path); -+ key->mtime = t; -+ key->type = APC_CACHE_KEY_FPFILE; ++ crc = n; ++ for (i = 8; i >= 0; i--) { ++ if (crc & 1) { ++ crc = (crc >> 1) ^ 0xEDB88320; + } -+ return 1; -+ } -+ -+ 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 = *tmp_buf; -+ } else { -+ if (apc_search_paths(filename, include_path, &fileinfo) != 0) { -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"Stat failed %s - bailing (%s) (%d)\n",filename,SG(request_info).path_translated); -+#endif -+ return 0; ++ else { ++ crc >>= 1; + } + } -+ -+ if(APCG(max_file_size) < fileinfo.st_buf.st_size) { -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"File is too big %s (%d - %ld) - bailing\n",filename,t,fileinfo.st_buf.st_size); ++ return crc; ++} +#endif -+ return 0; -+ } + -+ /* -+ * 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.st_mtime < APCG(file_update_protection))) { -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"File is too new %s (%d - %d) - bailing\n",filename,t,fileinfo.st_buf.st_mtime); -+#endif -+ return 0; -+ } ++/* }}} */ + -+ key->data.file.device = fileinfo.st_buf.st_dev; -+ key->data.file.inode = fileinfo.st_buf.st_ino; -+ /* -+ * 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.st_ctime > fileinfo.st_buf.st_mtime) ? fileinfo.st_buf.st_ctime : fileinfo.st_buf.st_mtime; -+ } else { -+ key->mtime = fileinfo.st_buf.st_mtime; ++ ++/* {{{ apc_flip_hash() */ ++HashTable* apc_flip_hash(HashTable *hash) { ++ zval **entry, *data; ++ HashTable *new_hash; ++ HashPosition pos; ++ ++ if(hash == NULL) return hash; ++ ++ MAKE_STD_ZVAL(data); ++ ZVAL_LONG(data, 1); ++ ++ new_hash = emalloc(sizeof(HashTable)); ++ zend_hash_init(new_hash, hash->nTableSize, NULL, ZVAL_PTR_DTOR, 0); ++ ++ zend_hash_internal_pointer_reset_ex(hash, &pos); ++ while (zend_hash_get_current_data_ex(hash, (void **)&entry, &pos) == SUCCESS) { ++ if(Z_TYPE_PP(entry) == IS_STRING) { ++ zend_hash_update(new_hash, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) +1, &data, sizeof(data), NULL); ++ } else { ++ zend_hash_index_update(new_hash, Z_LVAL_PP(entry), &data, sizeof(data), NULL); ++ } ++ Z_ADDREF_P(data); ++ zend_hash_move_forward_ex(hash, &pos); + } -+ key->type = APC_CACHE_KEY_FILE; -+ return 1; ++ zval_ptr_dtor(&data); ++ ++ return new_hash; +} +/* }}} */ + -+/* {{{ 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; ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_cache.c b/ext/apc/apc_cache.c +--- a/ext/apc/apc_cache.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_cache.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,1383 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | Rasmus Lerdorf | ++ | Arun C. Murthy | ++ | Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ + -+ key->data.user.identifier = identifier; -+ key->data.user.identifier_len = identifier_len; -+ key->mtime = t; -+ key->type = APC_CACHE_KEY_USER; -+ return 1; -+} -+/* }}} */ ++ 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. + -+/* {{{ 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_cache_entry_t* entry; ++ All other licensing and usage conditions are those of the PHP Group. + -+ entry = (apc_cache_entry_t*) apc_sma_malloc(sizeof(apc_cache_entry_t)); -+ if (!entry) return NULL; ++ */ + -+ entry->data.file.filename = apc_xstrdup(filename, apc_sma_malloc); -+ if(!entry->data.file.filename) { -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n"); -+#endif -+ apc_sma_free(entry); -+ return NULL; -+ } -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is [%s]\n",entry->data.file.filename); -+#endif -+ entry->data.file.op_array = op_array; -+ entry->data.file.functions = functions; -+ entry->data.file.classes = classes; -+ entry->type = APC_CACHE_ENTRY_FILE; -+ entry->ref_count = 0; -+ entry->mem_size = 0; -+ entry->autofiltered = 0; -+ entry->local = 0; -+ return entry; -+} -+/* }}} */ ++/* $Id: apc_cache.c 325482 2012-05-01 00:09:36Z rasmus $ */ + -+/* {{{ apc_cache_store_zval */ -+zval* apc_cache_store_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate) -+{ -+ smart_str buf = {0}; -+ php_serialize_data_t var_hash; -+ TSRMLS_FETCH(); ++#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" + -+ if((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) { -+ if(!dst) { -+ CHECK(dst = (zval*) allocate(sizeof(zval))); -+ } -+ -+ PHP_VAR_SERIALIZE_INIT(var_hash); -+ php_var_serialize(&buf, (zval**)&src, &var_hash TSRMLS_CC); -+ PHP_VAR_SERIALIZE_DESTROY(var_hash); -+ -+ dst->type = IS_NULL; /* in case we fail */ -+ if(buf.c) { -+ dst->type = src->type & ~IS_CONSTANT_INDEX; -+ dst->value.str.len = buf.len; -+ CHECK(dst->value.str.val = apc_xmemcpy(buf.c, buf.len+1, allocate)); -+ dst->type = src->type; -+ smart_str_free(&buf); -+ } -+ return dst; -+ } else { -+ -+ /* Maintain a list of zvals we've copied to properly handle recursive structures */ -+ HashTable *old = APCG(copied_zvals); -+ APCG(copied_zvals) = emalloc(sizeof(HashTable)); -+ zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0); -+ -+ dst = apc_copy_zval(dst, src, allocate, deallocate); ++/* TODO: rehash when load factor exceeds threshold */ + -+ if(APCG(copied_zvals)) { -+ zend_hash_destroy(APCG(copied_zvals)); -+ efree(APCG(copied_zvals)); -+ } ++#define CHECK(p) { if ((p) == NULL) return NULL; } + -+ APCG(copied_zvals) = old; ++/* {{{ key_equals */ ++#define key_equals(a, b) (a.inode==b.inode && a.device==b.device) ++/* }}} */ + -+ return dst; -+ } ++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); +} +/* }}} */ + -+/* {{{ apc_cache_fetch_zval */ -+zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ 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) +{ -+ TSRMLS_FETCH(); -+ if((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) { -+ php_unserialize_data_t var_hash; -+ const unsigned char *p = (unsigned char*)Z_STRVAL_P(src); -+ -+ PHP_VAR_UNSERIALIZE_INIT(var_hash); -+ if(!php_var_unserialize(&dst, &p, p + Z_STRLEN_P(src), &var_hash TSRMLS_CC)) { -+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash); -+ zval_dtor(dst); -+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - Z_STRVAL_P(src)), Z_STRLEN_P(src)); -+ dst->type = IS_NULL; -+ } -+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash); -+ return dst; -+ } else { -+ -+ /* Maintain a list of zvals we've copied to properly handle recursive structures */ -+ HashTable *old = APCG(copied_zvals); -+ APCG(copied_zvals) = emalloc(sizeof(HashTable)); -+ zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0); -+ -+ dst = apc_copy_zval(dst, src, allocate, deallocate); ++ const long m = 0x7fd652ad; ++ const long r = 16; ++ unsigned int h = 0xdeadbeef; + -+ if(APCG(copied_zvals)) { -+ zend_hash_destroy(APCG(copied_zvals)); -+ efree(APCG(copied_zvals)); -+ } ++ 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; ++ }; + -+ APCG(copied_zvals) = old; ++ h *= m; ++ h ^= h >> 10; ++ h *= m; ++ h ^= h >> 17; + -+ return dst; -+ } ++ return h; +} ++#endif +/* }}} */ + -+/* {{{ apc_cache_free_zval */ -+void apc_cache_free_zval(zval* src, apc_free_t deallocate) -+{ -+ TSRMLS_FETCH(); -+ if ((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) { -+ if (src->value.str.val) { -+ deallocate(src->value.str.val); -+ } -+ deallocate(src); -+ } else { -+ /* Maintain a list of zvals we've copied to properly handle recursive structures */ -+ HashTable *old = APCG(copied_zvals); -+ APCG(copied_zvals) = emalloc(sizeof(HashTable)); -+ zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0); -+ -+ apc_free_zval(src, deallocate); + -+ if(APCG(copied_zvals)) { -+ zend_hash_destroy(APCG(copied_zvals)); -+ efree(APCG(copied_zvals)); -+ } ++/* {{{ 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 */ ++}; + -+ APCG(copied_zvals) = old; ++static int make_prime(int n) ++{ ++ int *k = (int*)primes; ++ while(*k) { ++ if((*k) > n) return *k; ++ k++; + } ++ return *(k-1); +} +/* }}} */ + -+/* {{{ apc_cache_make_user_entry */ -+apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, const unsigned int ttl) ++/* {{{ make_slot */ ++slot_t* make_slot(apc_cache_key_t *key, apc_cache_entry_t* value, slot_t* next, time_t t TSRMLS_DC) +{ -+ apc_cache_entry_t* entry; ++ slot_t* p = apc_pool_alloc(value->pool, sizeof(slot_t)); + -+ entry = (apc_cache_entry_t*) apc_sma_malloc(sizeof(apc_cache_entry_t)); -+ if (!entry) return NULL; ++ if (!p) return NULL; + -+ entry->data.user.info = apc_xmemcpy(info, info_len, apc_sma_malloc); -+ entry->data.user.info_len = info_len; -+ if(!entry->data.user.info) { -+ apc_sma_free(entry); -+ return NULL; -+ } -+ entry->data.user.val = apc_cache_store_zval(NULL, val, apc_sma_malloc, apc_sma_free); -+ if(!entry->data.user.val) { -+ apc_sma_free(entry->data.user.info); -+ apc_sma_free(entry); -+ 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->autofiltered = 0; -+ entry->local = 0; -+ return entry; -+} -+/* }}} */ -+ -+/* {{{ apc_cache_free_entry */ -+void apc_cache_free_entry(apc_cache_entry_t* entry) -+{ -+ if (entry != NULL) { -+ assert(entry->ref_count == 0); -+ switch(entry->type) { -+ case APC_CACHE_ENTRY_FILE: -+ apc_sma_free(entry->data.file.filename); -+ apc_free_op_array(entry->data.file.op_array, apc_sma_free); -+ apc_free_functions(entry->data.file.functions, apc_sma_free); -+ apc_free_classes(entry->data.file.classes, apc_sma_free); -+ break; -+ case APC_CACHE_ENTRY_USER: -+ apc_sma_free(entry->data.user.info); -+ apc_cache_free_zval(entry->data.user.val, apc_sma_free); -+ break; ++ 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; + } -+ apc_sma_free(entry); ++ 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; +} +/* }}} */ + -+/* {{{ apc_cache_info */ -+apc_cache_info_t* apc_cache_info(apc_cache_t* cache, zend_bool limited) ++/* {{{ free_slot */ ++static void free_slot(slot_t* slot TSRMLS_DC) +{ -+ apc_cache_info_t* info; -+ slot_t* p; -+ int i; -+ -+ if(!cache) return NULL; -+ -+ LOCK(cache); -+ -+ info = (apc_cache_info_t*) apc_emalloc(sizeof(apc_cache_info_t)); -+ if(!info) { -+ UNLOCK(cache); -+ return NULL; -+ } -+ info->num_slots = cache->num_slots; -+ info->ttl = cache->ttl; -+ info->num_hits = cache->header->num_hits; -+ info->num_misses = cache->header->num_misses; -+ info->list = NULL; -+ info->deleted_list = NULL; -+ info->start_time = cache->header->start_time; -+ info->expunges = cache->header->expunges; -+ info->mem_size = cache->header->mem_size; -+ info->num_entries = cache->header->num_entries; -+ info->num_inserts = cache->header->num_inserts; -+ -+ if(!limited) { -+ /* For each hashtable slot */ -+ for (i = 0; i < info->num_slots; i++) { -+ p = cache->slots[i]; -+ for (; p != NULL; p = p->next) { -+ apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t)); -+ -+ if(p->value->type == APC_CACHE_ENTRY_FILE) { -+ link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc); -+ link->data.file.device = p->key.data.file.device; -+ link->data.file.inode = p->key.data.file.inode; -+ link->type = APC_CACHE_ENTRY_FILE; -+ } else if(p->value->type == APC_CACHE_ENTRY_USER) { -+ link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len, apc_emalloc); -+ link->data.user.ttl = p->value->data.user.ttl; -+ link->type = APC_CACHE_ENTRY_USER; -+ } -+ link->num_hits = p->num_hits; -+ link->mtime = p->key.mtime; -+ link->creation_time = p->creation_time; -+ link->deletion_time = p->deletion_time; -+ link->access_time = p->access_time; -+ link->ref_count = p->value->ref_count; -+ link->mem_size = p->value->mem_size; -+ link->next = info->list; -+ info->list = link; -+ } -+ } -+ -+ /* For each slot pending deletion */ -+ for (p = cache->header->deleted_list; p != NULL; p = p->next) { -+ apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t)); -+ -+ if(p->value->type == APC_CACHE_ENTRY_FILE) { -+ link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc); -+ if(p->key.type == APC_CACHE_KEY_FILE) { -+ link->data.file.device = p->key.data.file.device; -+ link->data.file.inode = p->key.data.file.inode; -+ } else { /* This is a no-stat fullpath file entry */ -+ link->data.file.device = 0; -+ link->data.file.inode = 0; -+ } -+ link->type = APC_CACHE_ENTRY_FILE; -+ } else if(p->value->type == APC_CACHE_ENTRY_USER) { -+ link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len, apc_emalloc); -+ link->data.user.ttl = p->value->data.user.ttl; -+ link->type = APC_CACHE_ENTRY_USER; -+ } -+ link->num_hits = p->num_hits; -+ link->mtime = p->key.mtime; -+ link->creation_time = p->creation_time; -+ link->deletion_time = p->deletion_time; -+ link->access_time = p->access_time; -+ link->ref_count = p->value->ref_count; -+ link->mem_size = p->value->mem_size; -+ link->next = info->deleted_list; -+ info->deleted_list = link; -+ } -+ } -+ -+ UNLOCK(cache); -+ return info; ++ apc_pool_destroy(slot->value->pool TSRMLS_CC); +} +/* }}} */ + -+/* {{{ apc_cache_free_info */ -+void apc_cache_free_info(apc_cache_info_t* info) ++/* {{{ remove_slot */ ++static void remove_slot(apc_cache_t* cache, slot_t** slot TSRMLS_DC) +{ -+ apc_cache_link_t* p = info->list; -+ apc_cache_link_t* q = NULL; -+ while (p != NULL) { -+ q = p; -+ p = p->next; -+ if(q->type == APC_CACHE_ENTRY_FILE) apc_efree(q->data.file.filename); -+ else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info); -+ apc_efree(q); ++ 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); + } -+ p = info->deleted_list; -+ while (p != NULL) { -+ q = p; -+ p = p->next; -+ if(q->type == APC_CACHE_ENTRY_FILE) apc_efree(q->data.file.filename); -+ else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info); -+ apc_efree(q); ++ else { ++ dead->next = cache->header->deleted_list; ++ dead->deletion_time = time(0); ++ cache->header->deleted_list = dead; + } -+ apc_efree(info); -+} -+/* }}} */ -+ -+/* {{{ apc_cache_unlock */ -+void apc_cache_unlock(apc_cache_t* cache) -+{ -+ UNLOCK(cache); +} +/* }}} */ + -+/* {{{ apc_cache_busy */ -+zend_bool apc_cache_busy(apc_cache_t* cache) ++/* {{{ process_pending_removals */ ++static void process_pending_removals(apc_cache_t* cache TSRMLS_DC) +{ -+ return cache->header->busy; -+} -+/* }}} */ ++ slot_t** slot; ++ time_t now; + -+#if NONBLOCKING_LOCK_AVAILABLE -+/* {{{ apc_cache_write_lock */ -+zend_bool apc_cache_write_lock(apc_cache_t* cache) -+{ -+ return apc_lck_nb_lock(cache->header->wrlock); -+} -+/* }}} */ ++ /* 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). ++ */ + -+/* {{{ apc_cache_write_unlock */ -+void apc_cache_write_unlock(apc_cache_t* cache) -+{ -+ apc_lck_unlock(cache->header->wrlock); -+} -+/* }}} */ -+#endif ++ if (!cache->header->deleted_list) ++ return; + -+/* {{{ make_local_slot */ -+static local_slot_t* make_local_slot(apc_local_cache_t* cache, local_slot_t* lslot, slot_t* slot) -+{ -+ apc_cache_entry_t* value; ++ slot = &cache->header->deleted_list; ++ now = time(0); + -+ value = apc_emalloc(sizeof(apc_cache_entry_t)); -+ memcpy(value, slot->value, sizeof(apc_cache_entry_t)); /* bitwise copy */ -+ value->local = 1; ++ while (*slot != NULL) { ++ int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0; + -+ lslot->original = slot; -+ lslot->value = value; -+ lslot->num_hits++; ++ if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) { ++ slot_t* dead = *slot; + -+ return lslot; /* for what joy ? ... consistency */ ++ 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; ++ } ++ } +} +/* }}} */ + -+/* {{{ free_local_slot */ -+static void free_local_slot(apc_local_cache_t* cache, local_slot_t* lslot) ++/* {{{ prevent_garbage_collection */ ++static void prevent_garbage_collection(apc_cache_entry_t* entry) +{ -+ local_slot_t * dead = NULL; -+ if(!lslot->original) return; -+ -+ /* TODO: Bad design to allocate memory in a free_* - fix when bored (hehe) */ -+ dead = apc_emalloc(sizeof(local_slot_t)); -+ memcpy(dead, lslot, sizeof(local_slot_t)); /* bitwise copy */ ++ /* set reference counts on zend objects to an arbitrarily high value to ++ * prevent garbage collection after execution */ + -+ lslot->original = NULL; -+ lslot->value = NULL; ++ enum { BIG_VALUE = 1000 }; + -+ dead->next = cache->dead_list; -+ cache->dead_list = dead; ++ 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_local_cache_create */ -+apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl) ++/* {{{ apc_cache_create */ ++apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC) +{ -+ apc_local_cache_t* cache = NULL; ++ apc_cache_t* cache; ++ int cache_size; ++ int num_slots; ++ ++ num_slots = make_prime(size_hint > 0 ? size_hint : 2000); + -+ cache = (apc_local_cache_t*) apc_emalloc(sizeof(apc_local_cache_t)); ++ cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t) TSRMLS_CC); ++ cache_size = sizeof(cache_header_t) + num_slots*sizeof(slot_t*); + -+ cache->slots = (local_slot_t*) (apc_emalloc(sizeof(local_slot_t) * num_slots)); -+ memset(cache->slots, 0, sizeof(local_slot_t) * num_slots); ++ 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->shmcache = shmcache; ++ cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(cache_header_t)); + cache->num_slots = num_slots; ++ cache->gc_ttl = gc_ttl; + cache->ttl = ttl; -+ cache->num_hits = 0; -+ cache->generation = shmcache->header->expunges; -+ cache->dead_list = NULL; ++ 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_local_cache_cleanup */ -+void apc_local_cache_cleanup(apc_local_cache_t* cache) { -+ local_slot_t * lslot; -+ time_t t = time(0); -+ -+ int i; -+ for(i = 0; i < cache->num_slots; i++) { -+ slot_t * slot = cache->slots[i].original; -+ if((slot && slot->access_time < (t - cache->ttl)) || -+ cache->generation != cache->shmcache->header->expunges) { -+ free_local_slot(cache, &cache->slots[i]); -+ } -+ } -+ -+ LOCK(cache->shmcache); -+ for(lslot = cache->dead_list; lslot != NULL; lslot = lslot->next) { -+ lslot->original->num_hits += lslot->num_hits; -+ lslot->original->value->ref_count--; /* apc_cache_release(cache->shmcache, lslot->original->value); */ -+ apc_efree(lslot->value); -+ } -+ UNLOCK(cache->shmcache); -+ -+ cache->dead_list = NULL; ++/* {{{ apc_cache_destroy */ ++void apc_cache_destroy(apc_cache_t* cache TSRMLS_DC) ++{ ++ DESTROY_LOCK(cache->header->lock); ++#if NONBLOCKING_LOCK_AVAILABLE ++ DESTROY_LOCK(cache->header->wrlock); ++#endif ++ apc_efree(cache TSRMLS_CC); +} +/* }}} */ + -+/* {{{ apc_local_cache_destroy */ -+void apc_local_cache_destroy(apc_local_cache_t* cache) ++/* {{{ apc_cache_clear */ ++void apc_cache_clear(apc_cache_t* cache TSRMLS_DC) +{ + int i; -+ for(i = 0; i < cache->num_slots; i++) { -+ free_local_slot(cache, &cache->slots[i]); -+ } + -+ apc_local_cache_cleanup(cache); ++ 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; ++ } + -+ LOCK(cache->shmcache); -+ cache->shmcache->header->num_hits += cache->num_hits; -+ UNLOCK(cache->shmcache); ++ memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t)); + -+ apc_efree(cache->slots); -+ apc_efree(cache); ++ cache->header->busy = 0; ++ CACHE_UNLOCK(cache); +} +/* }}} */ + -+/* {{{ apc_local_cache_find */ -+apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t) ++/* {{{ apc_cache_expunge */ ++static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC) +{ -+ slot_t* slot; -+ local_slot_t* lslot; ++ int i; ++ time_t t; + -+ if(key.type == APC_CACHE_KEY_FILE) lslot = &cache->slots[hash(key) % cache->num_slots]; -+ else lslot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots]; ++ t = apc_time(); + -+ slot = lslot->original; ++ if(!cache) return; + -+ if(slot && key.type == slot->key.type) { -+ if(slot->access_time < (t - cache->ttl)) { -+ goto not_found; ++ 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; + } -+ if(key.type == APC_CACHE_KEY_FILE && -+ key_equals(slot->key.data.file, key.data.file)) { -+ if(slot->key.mtime != key.mtime) { -+ free_local_slot(cache, lslot); -+ goto not_found; -+ } -+ return lslot->value; -+ } else if(key.type == APC_CACHE_KEY_FPFILE) { -+ if(!memcmp(slot->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) { -+ return lslot->value; ++ 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; + } -+ } -+not_found: -+ if(apc_cache_busy(cache->shmcache)) { -+ return 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 ++ */ + -+ slot = apc_cache_find_slot(cache->shmcache, key, t); ++ 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(!slot) return NULL; -+ -+ /* i.e maintain a sort of top list */ -+ if(lslot->original == NULL || (lslot->original->num_hits + lslot->num_hits) < slot->num_hits) { -+ free_local_slot(cache, lslot); -+ make_local_slot(cache, lslot, slot); -+ return lslot->value; ++ 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); + } -+ return slot->value; +} +/* }}} */ + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_cache.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_cache.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,313 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt. | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | Rasmus Lerdorf | -+ +----------------------------------------------------------------------+ -+ -+ This software was contributed to PHP by Community Connect Inc. in 2002 -+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. -+ Future revisions and derivatives of this source code must acknowledge -+ Community Connect Inc. as the original contributor of this module by -+ leaving this note intact in the source code. ++/* {{{ 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; + -+ All other licensing and usage conditions are those of the PHP Group. ++ if (!value) { ++ return 0; ++ } + -+ */ ++ apc_debug("Inserting [%s]\n" TSRMLS_CC, value->data.file.filename); + -+/* $Id: apc_cache.h,v 3.45 2007/03/22 16:03:59 gopalv Exp $ */ ++ process_pending_removals(cache TSRMLS_CC); + -+#ifndef APC_CACHE_H -+#define APC_CACHE_H ++ slot = &cache->slots[key.h % cache->num_slots]; + -+/* -+ * This module defines the shared memory file cache. Basically all of the -+ * logic for storing and retrieving cache entries lives here. -+ */ ++ 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; ++ } + -+#include "apc.h" -+#include "apc_compile.h" ++ if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) { ++ return -1; ++ } + -+#define APC_CACHE_ENTRY_FILE 1 -+#define APC_CACHE_ENTRY_USER 2 ++ 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); + -+#define APC_CACHE_KEY_FILE 1 -+#define APC_CACHE_KEY_USER 2 -+#define APC_CACHE_KEY_FPFILE 3 ++ return 1; ++} ++/* }}} */ + -+/* {{{ struct definition: apc_cache_key_t */ -+#define T apc_cache_t* -+typedef struct apc_cache_t apc_cache_t; /* opaque cache type */ ++/* {{{ 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; ++} ++/* }}} */ + -+typedef union _apc_cache_key_data_t { -+ struct { -+ dev_t device; /* the filesystem device */ -+ ino_t inode; /* the filesystem inode */ -+ } file; -+ struct { -+ const char *identifier; -+ int identifier_len; -+ } user; -+ struct { -+ const char *fullpath; -+ int fullpath_len; -+ } fpfile; -+} apc_cache_key_data_t; ++/* {{{ 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; + -+typedef struct apc_cache_key_t apc_cache_key_t; -+struct apc_cache_key_t { -+ apc_cache_key_data_t data; -+ time_t mtime; /* the mtime of this cached entry */ -+ unsigned char type; -+}; ++ 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; ++} +/* }}} */ + -+/* {{{ struct definition: apc_cache_entry_t */ -+typedef union _apc_cache_entry_value_t { -+ struct { -+ char *filename; /* absolute path to source file */ -+ zend_op_array* op_array; /* op_array allocated in shared memory */ -+ apc_function_t* functions; /* array of apc_function_t's */ -+ apc_class_t* classes; /* array of apc_class_t's */ -+ } file; -+ struct { -+ char *info; -+ int info_len; -+ zval *val; -+ unsigned int ttl; -+ } user; -+} apc_cache_entry_value_t; + -+typedef struct apc_cache_entry_t apc_cache_entry_t; -+struct apc_cache_entry_t { -+ apc_cache_entry_value_t data; -+ unsigned char type; -+ unsigned char autofiltered; -+ unsigned char local; -+ int ref_count; -+ size_t mem_size; -+}; -+/* }}} */ ++/* {{{ 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; ++ } + -+/* -+ * apc_cache_create creates the shared memory compiler cache. This function -+ * should be called just once (ideally in the web server parent process, e.g. -+ * in apache), otherwise you will end up with multiple caches (which won't -+ * necessarily break anything). Returns a pointer to the cache object. -+ * -+ * size_hint is a "hint" at the total number of source files that will be -+ * cached. It determines the physical size of the hash table. Passing 0 for -+ * this argument will use a reasonable default value. -+ * -+ * gc_ttl is the maximum time a cache entry may speed on the garbage -+ * collection list. This is basically a work around for the inherent -+ * unreliability of our reference counting mechanism (see apc_cache_release). -+ * -+ * ttl is the maximum time a cache entry can idle in a slot in case the slot -+ * is needed. This helps in cleaning up the cache and ensuring that entries -+ * hit frequently stay cached and ones not hit very often eventually disappear. -+ */ -+extern T apc_cache_create(int size_hint, int gc_ttl, int ttl); ++ if(apc_cache_is_last_key(cache, &key, t TSRMLS_CC)) { ++ /* potential cache slam */ ++ return 0; ++ } + -+/* -+ * apc_cache_destroy releases any OS resources associated with a cache object. -+ * Under apache, this function can be safely called by the child processes -+ * when they exit. -+ */ -+extern void apc_cache_destroy(T cache); ++ CACHE_LOCK(cache); + -+/* -+ * apc_cache_clear empties a cache. This can safely be called at any time, -+ * even while other server processes are executing cached source files. -+ */ -+extern void apc_cache_clear(T cache); ++ memset(lastkey, 0, sizeof(apc_keyid_t)); + -+/* -+ * apc_cache_insert adds an entry to the cache, using a filename as a key. -+ * Internally, the filename is translated to a canonical representation, so -+ * that relative and absolute filenames will map to a single key. Returns -+ * non-zero if the file was successfully inserted, 0 otherwise. If 0 is -+ * returned, the caller must free the cache entry by calling -+ * apc_cache_free_entry (see below). -+ * -+ * key is the value created by apc_cache_make_file_key for file keys. -+ * -+ * value is a cache entry returned by apc_cache_make_entry (see below). -+ */ -+extern int apc_cache_insert(T cache, apc_cache_key_t key, -+ apc_cache_entry_t* value, time_t 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. ++ */ + -+extern int apc_cache_user_insert(T cache, apc_cache_key_t key, -+ apc_cache_entry_t* value, time_t t, int exclusive TSRMLS_DC); ++ process_pending_removals(cache TSRMLS_CC); ++ ++ slot = &cache->slots[key.h % cache->num_slots]; + -+/* -+ * apc_cache_find searches for a cache entry by filename, and returns a -+ * pointer to the entry if found, NULL otherwise. -+ * -+ * key is a value created by apc_cache_make_file_key for file keys. -+ */ -+extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t); ++ 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; ++ } + -+/* -+ * apc_cache_user_find searches for a cache entry by its hashed identifier, -+ * and returns a pointer to the entry if found, NULL otherwise. -+ * -+ */ -+extern apc_cache_entry_t* apc_cache_user_find(T cache, char* strkey, int keylen, time_t t); ++ 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; + -+/* -+ * apc_cache_user_delete finds an entry in the user cache and deletes it. -+ */ -+extern int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen); ++ CACHE_FAST_INC(cache, cache->header->num_entries); ++ CACHE_FAST_INC(cache, cache->header->num_inserts); + -+/* apc_cach_fetch_zval takes a zval in the cache and reconstructs a runtime -+ * zval from it. -+ * -+ */ -+zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate); ++ CACHE_UNLOCK(cache); + -+/* -+ * apc_cache_release decrements the reference count associated with a cache -+ * entry. Calling apc_cache_find automatically increments the reference count, -+ * and this function must be called post-execution to return the count to its -+ * original value. Failing to do so will prevent the entry from being -+ * garbage-collected. -+ * -+ * entry is the cache entry whose ref count you want to decrement. -+ */ -+extern void apc_cache_release(T cache, apc_cache_entry_t* entry); ++ return 1; + -+/* -+ * apc_cache_make_file_key creates a key object given a relative or absolute -+ * filename and an optional list of auxillary paths to search. include_path is -+ * searched if the filename cannot be found relative to the current working -+ * directory. -+ * -+ * key points to caller-allocated storage (must not be null). -+ * -+ * filename is the path to the source file. -+ * -+ * include_path is a colon-separated list of directories to search. -+ * -+ * and finally we pass in the current request time so we can avoid -+ * caching files with a current mtime which tends to indicate that -+ * they are still being written to. -+ */ -+extern int apc_cache_make_file_key(apc_cache_key_t* key, -+ const char* filename, -+ const char* include_path, -+ time_t t -+ TSRMLS_DC); ++fail: ++ CACHE_UNLOCK(cache); + -+/* -+ * apc_cache_make_file_entry creates an apc_cache_entry_t object given a filename -+ * and the compilation results returned by the PHP compiler. -+ */ -+extern 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_cache_make_user_entry creates an apc_cache_entry_t object given an info string -+ * and the zval to be stored. -+ */ -+extern apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval *val, const unsigned int ttl); -+ -+extern int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t); ++ return 0; ++} ++/* }}} */ + -+/* -+ * Frees all memory associated with an object returned by apc_cache_make_entry -+ * (see above). -+ */ -+extern void apc_cache_free_entry(apc_cache_entry_t* entry); ++/* {{{ 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; + -+/* {{{ struct definition: apc_cache_link_data_t */ -+typedef union _apc_cache_link_data_t { -+ struct { -+ char *filename; -+ dev_t device; -+ ino_t inode; -+ } file; -+ struct { -+ char *info; -+ unsigned int ttl; -+ } user; -+} apc_cache_link_data_t; -+/* }}} */ ++ 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]; + -+/* {{{ struct definition: apc_cache_link_t */ -+typedef struct apc_cache_link_t apc_cache_link_t; -+struct apc_cache_link_t { -+ apc_cache_link_data_t data; -+ unsigned char type; -+ int num_hits; -+ time_t mtime; -+ time_t creation_time; -+ time_t deletion_time; -+ time_t access_time; -+ int ref_count; -+ size_t mem_size; -+ apc_cache_link_t* next; -+}; ++ 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; ++} +/* }}} */ + -+/* {{{ struct definition: apc_cache_info_t */ -+typedef struct apc_cache_info_t apc_cache_info_t; -+struct apc_cache_info_t { -+ int num_slots; -+ int num_hits; -+ int num_misses; -+ int ttl; -+ apc_cache_link_t* list; -+ apc_cache_link_t* deleted_list; -+ time_t start_time; -+ int expunges; -+ int num_entries; -+ int num_inserts; -+ size_t mem_size; -+}; ++/* {{{ 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; ++} +/* }}} */ + -+extern apc_cache_info_t* apc_cache_info(T cache, zend_bool limited); -+extern void apc_cache_free_info(apc_cache_info_t* info); -+extern void apc_cache_expunge(apc_cache_t* cache, time_t t); -+extern void apc_cache_unlock(apc_cache_t* cache); -+extern zend_bool apc_cache_busy(apc_cache_t* cache); -+extern zend_bool apc_cache_write_lock(apc_cache_t* cache); -+extern void apc_cache_write_unlock(apc_cache_t* cache); -+ -+/* -+ * Process local cache, which keeps a refcount hungry version of the slots -+ * for quick access without a lock - as long as the entry exists in local -+ * cache, the refcount of the shm version will be +1 more than required. -+ * It holds no data, only a shallow copy of apc_cache_entry. -+ */ -+typedef struct apc_local_cache_t apc_local_cache_t; /* process-local cache */ -+ -+extern apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl); -+extern apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t); -+extern void apc_local_cache_destroy(apc_local_cache_t* cache); -+extern void apc_local_cache_cleanup(apc_local_cache_t* cache); -+ -+#undef T -+#endif -+ -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_compile.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_compile.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,2530 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt. | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | Rasmus Lerdorf | -+ | Arun C. Murthy | -+ | Gopal Vijayaraghavan | -+ +----------------------------------------------------------------------+ -+ -+ 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. ++/* {{{ 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; + -+ All other licensing and usage conditions are those of the PHP Group. ++ if(apc_cache_busy(cache)) ++ { ++ /* cache cleanup in progress */ ++ return NULL; ++ } + -+ */ ++ CACHE_RDLOCK(cache); + -+/* $Id: apc_compile.c,v 3.85 2007/03/28 07:35:55 gopalv Exp $ */ ++ h = string_nhash_8(strkey, keylen); + -+#include "apc_compile.h" -+#include "apc_globals.h" -+#include "apc_zend.h" ++ slot = &cache->slots[h % cache->num_slots]; + -+typedef void* (*ht_copy_fun_t)(void*, void*, apc_malloc_t, apc_free_t); -+typedef void (*ht_free_fun_t)(void*, apc_free_t); -+typedef int (*ht_check_copy_fun_t)(Bucket*, va_list); ++ 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; + -+#ifdef ZEND_ENGINE_2 -+typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*); -+#endif ++ 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; ++} ++/* }}} */ + -+#define CHECK(p) { if ((p) == NULL) 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; + -+/* {{{ internal function declarations */ ++ if(apc_cache_busy(cache)) ++ { ++ /* cache cleanup in progress */ ++ return NULL; ++ } + -+static int is_derived_class(zend_op_array* op_array, const char* key, int key_size); ++ CACHE_RDLOCK(cache); + -+static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_malloc_t); ++ h = string_nhash_8(strkey, keylen); + -+/* -+ * The "copy" functions perform deep-copies on a particular data structure -+ * (passed as the second argument). They also optionally allocate space for -+ * the destination data structure if the first argument is null. -+ */ -+static zval** my_copy_zval_ptr(zval**, const zval**, apc_malloc_t, apc_free_t); -+static zval* my_copy_zval(zval*, const zval*, apc_malloc_t, apc_free_t); -+static znode* my_copy_znode(znode*, znode*, apc_malloc_t, apc_free_t); -+static zend_op* my_copy_zend_op(zend_op*, zend_op*, apc_malloc_t, apc_free_t); -+static zend_function* my_copy_function(zend_function*, zend_function*, apc_malloc_t, apc_free_t); -+static zend_function_entry* my_copy_function_entry(zend_function_entry*, zend_function_entry*, apc_malloc_t, apc_free_t); -+static zend_class_entry* my_copy_class_entry(zend_class_entry*, zend_class_entry*, apc_malloc_t, apc_free_t); -+static HashTable* my_copy_hashtable_ex(HashTable*, HashTable*, ht_copy_fun_t, ht_free_fun_t, int, apc_malloc_t, apc_free_t, ht_check_copy_fun_t, ...); -+#define my_copy_hashtable( dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate) \ -+ my_copy_hashtable_ex(dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate, NULL) -+static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate); -+#ifdef ZEND_ENGINE_2 -+static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate); -+static zend_arg_info* my_copy_arg_info_array(zend_arg_info*, zend_arg_info*, uint, apc_malloc_t, apc_free_t); -+static zend_arg_info* my_copy_arg_info(zend_arg_info*, zend_arg_info*, apc_malloc_t, apc_free_t); -+#endif -+/* -+ * The "destroy" functions free the memory associated with a particular data -+ * structure but do not free the pointer to the data structure. -+ * -+ * my_destroy_zval() returns SUCCESS or FAILURE, FAILURE means that -+ * the zval* has other references elsewhere -+ */ -+static int my_destroy_zval(zval*, apc_free_t); -+static void my_destroy_zval_ptr(zval**, apc_free_t); -+static void my_destroy_zend_op(zend_op*, apc_free_t); -+static void my_destroy_znode(znode*, apc_free_t); -+static void my_destroy_function(zend_function*, apc_free_t); -+static void my_destroy_function_entry(zend_function_entry*, apc_free_t); -+static void my_destroy_class_entry(zend_class_entry*, apc_free_t); -+static void my_destroy_hashtable(HashTable*, ht_free_fun_t, apc_free_t); -+static void my_destroy_op_array(zend_op_array*, apc_free_t); -+#ifdef ZEND_ENGINE_2 -+static void my_destroy_property_info(zend_property_info*, apc_free_t); -+static void my_destroy_arg_info_array(zend_arg_info* src, uint, apc_free_t); -+static void my_destroy_arg_info(zend_arg_info*, apc_free_t); -+#endif ++ slot = &cache->slots[h % cache->num_slots]; + -+/* -+ * The "free" functions work exactly like their "destroy" counterparts (see -+ * above) but also free the pointer to the data structure. -+ */ -+static void my_free_zval_ptr(zval**, apc_free_t); -+static void my_free_function(zend_function*, apc_free_t); -+static void my_free_hashtable(HashTable*, ht_free_fun_t, apc_free_t); -+#ifdef ZEND_ENGINE_2 -+static void my_free_property_info(zend_property_info* src, apc_free_t); -+static void my_free_arg_info_array(zend_arg_info*, uint, apc_free_t); -+static void my_free_arg_info(zend_arg_info*, apc_free_t); -+#endif ++ 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; ++} ++/* }}} */ + -+/* -+ * The "fixup" functions need for ZEND_ENGINE_2 -+ */ -+#ifdef ZEND_ENGINE_2 -+static void my_fixup_function( Bucket *p, zend_class_entry *src, zend_class_entry *dst ); -+static void my_fixup_hashtable( HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst ); -+/* my_fixup_function_for_execution is the same as my_fixup_function -+ * but named differently for clarity -+ */ -+#define my_fixup_function_for_execution my_fixup_function ++/* {{{ 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; + -+#ifdef ZEND_ENGINE_2_2 -+static void my_fixup_property_info( Bucket *p, zend_class_entry *src, zend_class_entry *dst ); -+#define my_fixup_property_info_for_execution my_fixup_property_info -+#endif ++ if(apc_cache_busy(cache)) ++ { ++ /* cache cleanup in progress */ ++ return 0; ++ } + -+#endif ++ CACHE_LOCK(cache); + -+/* -+ * These functions return "1" if the member/function is -+ * defined/overridden in the 'current' class and not inherited. -+ */ -+static int my_check_copy_function(Bucket* src, va_list args); -+static int my_check_copy_default_property(Bucket* p, va_list args); -+#ifdef ZEND_ENGINE_2 -+static int my_check_copy_property_info(Bucket* src, va_list args); -+static int my_check_copy_static_member(Bucket* src, va_list args); -+#endif ++ 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; ++} +/* }}} */ + -+/* {{{ check_op_array_integrity */ -+#if 0 -+static void check_op_array_integrity(zend_op_array* src) ++/* {{{ apc_cache_user_delete */ ++int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC) +{ -+ int i, j; ++ slot_t** slot; ++ unsigned long h; + -+ /* These sorts of checks really aren't particularly effective, but they -+ * can provide a welcome sanity check when debugging. Just don't enable -+ * for production use! */ ++ CACHE_LOCK(cache); + -+ assert(src->refcount != NULL); -+ assert(src->opcodes != NULL); -+ assert(src->last > 0); ++ h = string_nhash_8(strkey, keylen); + -+ for (i = 0; i < src->last; i++) { -+ zend_op* op = &src->opcodes[i]; -+ znode* nodes[] = { &op->result, &op->op1, &op->op2 }; -+ for (j = 0; j < 3; j++) { -+ assert(nodes[j]->op_type == IS_CONST || -+ nodes[j]->op_type == IS_VAR || -+ nodes[j]->op_type == IS_TMP_VAR || -+ nodes[j]->op_type == IS_UNUSED); ++ slot = &cache->slots[h % cache->num_slots]; + -+ if (nodes[j]->op_type == IS_CONST) { -+ int type = nodes[j]->u.constant.type; -+ assert(type == IS_RESOURCE || -+ type == IS_BOOL || -+ type == IS_LONG || -+ type == IS_DOUBLE || -+ type == IS_NULL || -+ type == IS_CONSTANT || -+ type == IS_STRING || -+ type == FLAG_IS_BC || -+ type == IS_ARRAY || -+ type == IS_CONSTANT_ARRAY || -+ type == IS_OBJECT); -+ } ++ 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; +} -+#endif +/* }}} */ + -+/* {{{ is_derived_class */ -+static int is_derived_class(zend_op_array* op_array, const char* key, int key_size) ++/* {{{ apc_cache_delete */ ++int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC) +{ -+ int i; ++ slot_t** slot; ++ time_t t; ++ apc_cache_key_t key; + -+ /* -+ * Scan the op_array for execution-time class declarations of derived -+ * classes. If we find one whose key matches our current class key, we -+ * know the current class is a derived class. -+ * -+ * This check is exceedingly inefficient (fortunately it only has to occur -+ * once, when the source file is first compiled and cached), but the -+ * compiler should save this information for us -- definitely a candidate -+ * for a Zend Engine patch. -+ * -+ * XXX checking for derived classes provides a minimal (albeit measurable) -+ * speed up. It may not be worth the added complexity -- considere -+ * removing this optimization. -+ */ ++ t = apc_time(); + -+ for (i = 0; i < op_array->last; i++) { -+ zend_op* op = &op_array->opcodes[i]; -+ -+#ifdef ZEND_ENGINE_2 -+ if (op->opcode == ZEND_DECLARE_CLASS && -+ op->extended_value == ZEND_DECLARE_INHERITED_CLASS) -+#else -+ if (op->opcode == ZEND_DECLARE_FUNCTION_OR_CLASS && -+ op->extended_value == ZEND_DECLARE_INHERITED_CLASS) -+#endif -+ { -+ if (op->op1.u.constant.value.str.len == key_size && -+ !memcmp(op->op1.u.constant.value.str.val, key, key_size)) -+ { ++ /* 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; ++ +} +/* }}} */ + -+/* {{{ my_bitwise_copy_function */ -+static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate) ++/* {{{ apc_cache_release */ ++void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry TSRMLS_DC) +{ -+ assert(src != NULL); ++ CACHE_SAFE_DEC(cache, entry->ref_count); ++} ++/* }}} */ + -+ if (!dst) { -+ CHECK(dst = (zend_function*) allocate(sizeof(src[0]))); ++/* {{{ 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; + } + -+ /* We only need to do a bitwise copy */ -+ memcpy(dst, src, sizeof(src[0])); ++ len = strlen(filename); ++ if(APCG(fpstat)==0) { ++ if(IS_ABSOLUTE_PATH(filename,len) || strstr(filename, "://")) { ++ 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)) { + -+ return dst; -+} -+/* }}} */ ++ fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC); + -+/* {{{ my_copy_zval_ptr */ -+static zval** my_copy_zval_ptr(zval** dst, const zval** src, apc_malloc_t allocate, apc_free_t deallocate) -+{ -+ int local_dst_alloc = 0; -+ zval* dst_new; -+ -+ assert(src != NULL); ++ 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 (!dst) { -+ CHECK(dst = (zval**) allocate(sizeof(zval*))); -+ local_dst_alloc = 1; ++ 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 */ + } + -+ if(!(dst[0] = (zval*) allocate(sizeof(zval)))) { -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; ++ 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 */ + } -+ dst_new = my_copy_zval(*dst, *src, allocate, deallocate); -+ if(dst_new != *dst) { -+ deallocate(*dst); -+ *dst = dst_new; ++ ++ 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); + } + -+ (*dst)->refcount = (*src)->refcount; -+ (*dst)->is_ref = (*src)->is_ref; ++ return 1; ++ ++cleanup: + -+ return dst; ++ if(fileinfo != NULL) { ++ apc_php_free(fileinfo TSRMLS_CC); ++ } ++ ++ return 0; +} +/* }}} */ + -+/* {{{ my_copy_zval */ -+static zval* my_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ 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) +{ -+ zval **tmp; -+ TSRMLS_FETCH(); -+ -+ assert(dst != NULL); -+ assert(src != NULL); -+ -+ memcpy(dst, src, sizeof(src[0])); -+ -+ switch (src->type & ~IS_CONSTANT_INDEX) { -+ case IS_RESOURCE: -+ case IS_BOOL: -+ case IS_LONG: -+ case IS_DOUBLE: -+ case IS_NULL: -+ break; ++ assert(key != NULL); + -+ case IS_CONSTANT: -+ case IS_STRING: -+#ifndef ZEND_ENGINE_2 -+ case FLAG_IS_BC: -+#endif -+ if (src->value.str.val) { -+ CHECK(dst->value.str.val = apc_xmemcpy(src->value.str.val, -+ src->value.str.len+1, -+ allocate)); -+ } -+ break; -+ -+ case IS_ARRAY: ++ if (!identifier) ++ return 0; + -+ if(APCG(copied_zvals)) { -+ if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) { -+ (*tmp)->refcount++; -+ return *tmp; -+ } -+ -+ zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&dst, sizeof(zval*), NULL); -+ } -+ /* fall through */ -+ -+ case IS_CONSTANT_ARRAY: ++ 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; ++} ++/* }}} */ + -+ CHECK(dst->value.ht = -+ my_copy_hashtable(NULL, -+ src->value.ht, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ allocate, deallocate)); -+ break; ++/* {{{ 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; + -+ case IS_OBJECT: -+#ifndef ZEND_ENGINE_2 -+ CHECK(dst->value.obj.ce = -+ my_copy_class_entry(NULL, src->value.obj.ce, allocate, deallocate)); -+ -+ if(!(dst->value.obj.properties = my_copy_hashtable(NULL, -+ src->value.obj.properties, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ allocate, deallocate))) { -+ my_destroy_class_entry(dst->value.obj.ce, deallocate); -+ return NULL; -+ } -+ break; -+#else -+ dst->type = IS_NULL; -+#endif -+ break; ++ entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t)); ++ if (!entry) return NULL; + -+ default: -+ assert(0); ++ 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; + -+ return dst; ++ 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; +} +/* }}} */ + -+/* {{{ my_copy_znode */ -+static znode* my_copy_znode(znode* dst, znode* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ apc_cache_store_zval */ ++zval* apc_cache_store_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ assert(dst != NULL); -+ assert(src != NULL); ++ 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); ++ } + -+ memcpy(dst, src, sizeof(src[0])); + -+#ifdef IS_CV -+ assert(dst ->op_type == IS_CONST || -+ dst ->op_type == IS_VAR || -+ dst ->op_type == IS_CV || -+ dst ->op_type == IS_TMP_VAR || -+ dst ->op_type == IS_UNUSED); -+#else -+ assert(dst ->op_type == IS_CONST || -+ dst ->op_type == IS_VAR || -+ dst ->op_type == IS_TMP_VAR || -+ dst ->op_type == IS_UNUSED); -+#endif ++ return dst; ++} ++/* }}} */ + -+ if (src->op_type == IS_CONST) { -+ if(!my_copy_zval(&dst->u.constant, &src->u.constant, allocate, deallocate)) { -+ return NULL; -+ } ++/* {{{ 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; +} +/* }}} */ + -+/* {{{ my_copy_zend_op */ -+static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ 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) +{ -+ assert(dst != NULL); -+ assert(src != NULL); ++ apc_cache_entry_t* entry; ++ apc_pool* pool = ctxt->pool; + -+ memcpy(dst, src, sizeof(src[0])); ++ entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t)); ++ if (!entry) return NULL; + -+ if( my_copy_znode(&dst->result, &src->result, allocate, deallocate) == NULL -+ || my_copy_znode(&dst->op1, &src->op1, allocate, deallocate) == NULL -+ || my_copy_znode(&dst->op2, &src->op2, allocate, deallocate) == 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; + } -+ -+ return dst; ++ 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; +} +/* }}} */ + -+/* {{{ my_copy_function */ -+static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ */ ++static zval* apc_cache_link_info(apc_cache_t *cache, slot_t* p TSRMLS_DC) +{ -+ int local_dst_alloc = 0; -+ TSRMLS_FETCH(); ++ zval *link = NULL; ++ char md5str[33]; + -+ assert(src != NULL); ++ ALLOC_INIT_ZVAL(link); + -+ if(!dst) local_dst_alloc = 1; -+ CHECK(dst = my_bitwise_copy_function(dst, src, allocate)); ++ if(!link) { ++ return NULL; ++ } + -+ switch (src->type) { -+ case ZEND_INTERNAL_FUNCTION: -+ case ZEND_OVERLOADED_FUNCTION: -+ /* shallow copy because op_array is internal */ -+ dst->op_array = src->op_array; -+ break; -+ -+ case ZEND_USER_FUNCTION: -+ case ZEND_EVAL_CODE: -+ if(!apc_copy_op_array(&dst->op_array, -+ &src->op_array, -+ allocate, deallocate TSRMLS_CC)) { -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; -+ } -+ break; ++ array_init(link); + -+ default: -+ assert(0); -+ } -+#ifdef ZEND_ENGINE_2 -+ /* -+ * op_array bitwise copying overwrites what ever you modified -+ * before apc_copy_op_array - which is why this code is outside -+ * my_bitwise_copy_function. -+ */ ++ if(p->value->type == APC_CACHE_ENTRY_FILE) { ++ add_assoc_string(link, "type", "file", 1); ++ if(p->key.type == APC_CACHE_KEY_FILE) { + -+ /* zend_do_inheritance will re-look this up, because the pointers -+ * in prototype are from a function table of another class. It just -+ * helps if that one is from EG(class_table). -+ */ -+ dst->common.prototype = NULL; ++ #ifdef PHP_WIN32 ++ { ++ char buf[20]; ++ sprintf(buf, "%I64d", p->key.data.file.device); ++ add_assoc_string(link, "device", buf, 1); + -+ /* once a method is marked as ZEND_ACC_IMPLEMENTED_ABSTRACT then you -+ * have to carry around a prototype. Thankfully zend_do_inheritance -+ * sets this properly as well -+ */ -+ dst->common.fn_flags = src->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT); -+#endif ++ 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 dst; ++ return link; +} +/* }}} */ + -+/* {{{ my_copy_function_entry */ -+static zend_function_entry* my_copy_function_entry(zend_function_entry* dst, zend_function_entry* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ apc_cache_info */ ++zval* apc_cache_info(apc_cache_t* cache, zend_bool limited TSRMLS_DC) +{ -+ int local_dst_alloc = 0; -+ assert(src != NULL); -+ -+ if (!dst) { -+ CHECK(dst = (zend_function_entry*) allocate(sizeof(src[0]))); -+ local_dst_alloc = 1; -+ } ++ zval *info = NULL; ++ zval *list = NULL; ++ zval *deleted_list = NULL; ++ zval *slots = NULL; ++ slot_t* p; ++ int i, j; + -+ /* Start with a bitwise copy */ -+ memcpy(dst, src, sizeof(src[0])); ++ if(!cache) return NULL; + -+ dst->fname = NULL; -+#ifdef ZEND_ENGINE_2 -+ dst->arg_info = NULL; -+#else -+ dst->func_arg_types = NULL; -+#endif ++ CACHE_RDLOCK(cache); + -+ if (src->fname) { -+ if(!(dst->fname = apc_xstrdup(src->fname, allocate))) { -+ goto cleanup; -+ } -+ } ++ ALLOC_INIT_ZVAL(info); + -+#ifdef ZEND_ENGINE_2 -+ if (src->arg_info) { -+ if(!(dst->arg_info = my_copy_arg_info_array(NULL, -+ src->arg_info, -+ src->num_args, -+ allocate, -+ deallocate))) { -+ goto cleanup; -+ } -+ } -+#else -+ if (src->func_arg_types) { -+ if(!(dst->func_arg_types = apc_xmemcpy(src->func_arg_types, -+ src->func_arg_types[0]+1, -+ allocate))) { -+ goto cleanup; -+ } ++ if(!info) { ++ CACHE_RDUNLOCK(cache); ++ return NULL; + } -+#endif + -+ return dst; -+ -+cleanup: -+ if(dst->fname) deallocate(dst->fname); -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; -+} -+/* }}} */ ++ array_init(info); ++ add_assoc_long(info, "num_slots", cache->num_slots); ++ add_assoc_long(info, "ttl", cache->ttl); + -+#ifdef ZEND_ENGINE_2 -+/* {{{ my_copy_property_info */ -+static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate) -+{ -+ int local_dst_alloc = 0; ++ 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); + -+ assert(src != NULL); -+ -+ if (!dst) { -+ CHECK(dst = (zend_property_info*) allocate(sizeof(*src))); -+ local_dst_alloc = 1; -+ } ++ 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); + -+ /* Start with a bitwise copy */ -+ memcpy(dst, src, sizeof(*src)); ++ if(!limited) { ++ /* For each hashtable slot */ ++ ALLOC_INIT_ZVAL(list); ++ array_init(list); + -+ dst->name = NULL; -+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0 -+ dst->doc_comment = NULL; -+#endif ++ ALLOC_INIT_ZVAL(slots); ++ array_init(slots); + -+ if (src->name) { -+ /* private members are stored inside property_info as a mangled -+ * string of the form: -+ * \0\0\0 -+ */ -+ if(!(dst->name = -+ apc_xmemcpy(src->name, src->name_length+1, allocate))) { -+ goto cleanup; ++ 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++; ++ } ++ if(j != 0) { ++ add_index_long(slots, (ulong)i, j); ++ } + } -+ } + -+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0 -+ if (src->doc_comment) { -+ if( !(dst->doc_comment = -+ apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) { -+ goto cleanup; ++ /* 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); + } -+#endif -+ -+ return dst; + -+cleanup: -+ if(dst->name) deallocate(dst->name); -+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0 -+ if(dst->doc_comment) deallocate(dst->doc_comment); -+#endif -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; ++ CACHE_RDUNLOCK(cache); ++ return info; +} +/* }}} */ + -+/* {{{ my_copy_property_info_for_execution */ -+static zend_property_info* my_copy_property_info_for_execution(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ apc_cache_unlock */ ++void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC) +{ -+ int local_dst_alloc = 0; -+ -+ assert(src != NULL); -+ -+ if (!dst) { -+ CHECK(dst = (zend_property_info*) allocate(sizeof(*src))); -+ local_dst_alloc = 1; -+ } -+ -+ /* We need only a shallow copy */ -+ memcpy(dst, src, sizeof(*src)); -+ -+ return dst; ++ CACHE_UNLOCK(cache); +} +/* }}} */ + -+/* {{{ my_copy_arg_info_array */ -+static zend_arg_info* my_copy_arg_info_array(zend_arg_info* dst, zend_arg_info* src, uint num_args, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ apc_cache_busy */ ++zend_bool apc_cache_busy(apc_cache_t* cache) +{ -+ int local_dst_alloc = 0; -+ int i = 0; ++ return cache->header->busy; ++} ++/* }}} */ + -+ -+ if (!dst) { -+ CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)*num_args)); -+ local_dst_alloc = 1; -+ } ++/* {{{ 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 + -+ /* Start with a bitwise copy */ -+ memcpy(dst, src, sizeof(*src)*num_args); + -+ for(i=0; i < num_args; i++) { -+ if(!(my_copy_arg_info( &dst[i], &src[i], allocate, deallocate))) { -+ if(i) my_destroy_arg_info_array(dst, i-1, deallocate); -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; ++ /* 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 dst; ++ return 0; +} +/* }}} */ + -+/* {{{ my_copy_arg_info */ -+static zend_arg_info* my_copy_arg_info(zend_arg_info* dst, zend_arg_info* src, apc_malloc_t allocate, apc_free_t deallocate) ++#if NONBLOCKING_LOCK_AVAILABLE ++/* {{{ apc_cache_write_lock */ ++zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC) +{ -+ int local_dst_alloc = 0; -+ -+ assert(src != NULL); ++ return apc_lck_nb_lock(cache->header->wrlock); ++} ++/* }}} */ + -+ if (!dst) { -+ CHECK(dst = (zend_arg_info*) allocate(sizeof(*src))); -+ local_dst_alloc = 1; -+ } ++/* {{{ apc_cache_write_unlock */ ++void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC) ++{ ++ apc_lck_unlock(cache->header->wrlock); ++} ++/* }}} */ ++#endif + -+ /* Start with a bitwise copy */ -+ memcpy(dst, src, sizeof(*src)); ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_cache.h b/ext/apc/apc_cache.h +--- a/ext/apc/apc_cache.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_cache.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,371 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ + -+ dst->name = NULL; -+ dst->class_name = NULL; ++ 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. + -+ if (src->name) { -+ if(!(dst->name = -+ apc_xmemcpy(src->name, src->name_len+1, allocate))) { -+ goto cleanup; -+ } -+ } ++ All other licensing and usage conditions are those of the PHP Group. + -+ if (src->class_name) { -+ if(!(dst->class_name = -+ apc_xmemcpy(src->class_name, src->class_name_len+1, allocate))) { -+ goto cleanup; -+ } -+ } ++ */ + -+ return dst; ++/* $Id: apc_cache.h 324329 2012-03-18 15:29:37Z mike $ */ + -+cleanup: -+ if(dst->name) deallocate(dst->name); -+ if(dst->class_name) deallocate(dst->name); -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; -+} -+/* }}} */ -+#endif ++#ifndef APC_CACHE_H ++#define APC_CACHE_H + -+/* {{{ my_copy_class_entry */ -+static zend_class_entry* my_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate) -+{ -+ int local_dst_alloc = 0; -+ int i = 0; ++/* ++ * This module defines the shared memory file cache. Basically all of the ++ * logic for storing and retrieving cache entries lives here. ++ */ + -+ assert(src != NULL); ++#include "apc.h" ++#include "apc_compile.h" ++#include "apc_lock.h" ++#include "apc_pool.h" ++#include "apc_main.h" ++#include "TSRM.h" + -+ if (!dst) { -+ CHECK(dst = (zend_class_entry*) allocate(sizeof(*src))); -+ local_dst_alloc = 1; -+ } ++#define APC_CACHE_ENTRY_FILE 1 ++#define APC_CACHE_ENTRY_USER 2 + -+ /* Start with a bitwise copy */ -+ memcpy(dst, src, sizeof(*src)); ++#define APC_CACHE_KEY_FILE 1 ++#define APC_CACHE_KEY_USER 2 ++#define APC_CACHE_KEY_FPFILE 3 + -+ dst->name = NULL; -+ dst->builtin_functions = NULL; -+ memset(&dst->function_table, 0, sizeof(dst->function_table)); -+ memset(&dst->default_properties, 0, sizeof(dst->default_properties)); -+#ifndef ZEND_ENGINE_2 -+ dst->refcount = NULL; ++#ifdef PHP_WIN32 ++typedef unsigned __int64 apc_ino_t; ++typedef unsigned __int64 apc_dev_t; +#else -+ dst->static_members = NULL; -+ dst->doc_comment = NULL; -+ dst->filename = NULL; -+ memset(&dst->properties_info, 0, sizeof(dst->properties_info)); -+ memset(&dst->constants_table, 0, sizeof(dst->constants_table)); -+ memset(&dst->default_static_members, 0, sizeof(dst->default_static_members)); ++typedef ino_t apc_ino_t; ++typedef dev_t apc_dev_t; +#endif + -+ if (src->name) { -+ if(!(dst->name = apc_xstrdup(src->name, allocate))) { -+ goto cleanup; -+ } -+ } -+ -+#ifndef ZEND_ENGINE_2 -+ if(!(dst->refcount = apc_xmemcpy(src->refcount, -+ sizeof(src->refcount[0]), -+ allocate))) { -+ goto cleanup; -+ } -+#endif -+ -+ if(!(my_copy_hashtable_ex(&dst->function_table, -+ &src->function_table, -+ (ht_copy_fun_t) my_copy_function, -+ (ht_free_fun_t) my_free_function, -+ 0, -+ allocate, deallocate, -+ (ht_check_copy_fun_t) my_check_copy_function, -+ src))) { -+ goto cleanup; -+ } -+ -+#ifdef ZEND_ENGINE_2 -+ -+ /* the interfaces are populated at runtime using ADD_INTERFACE */ -+ dst->interfaces = NULL; -+ -+ /* the current count includes inherited interfaces as well, -+ the real dynamic ones are the first which are zero'd -+ out in zend_do_end_class_declaration */ -+ for(i = 0 ; i < src->num_interfaces ; i++) { -+ if(src->interfaces[i]) -+ { -+ dst->num_interfaces = i; -+ break; -+ } -+ } -+ -+ /* these will either be set inside my_fixup_hashtable or -+ * they will be copied out from parent inside zend_do_inheritance -+ */ -+ dst->constructor = NULL; -+ dst->destructor = NULL; -+ dst->clone = NULL; -+ dst->__get = NULL; -+ dst->__set = NULL; -+ dst->__unset = NULL; -+ dst->__isset = NULL; -+ dst->__call = NULL; -+#ifdef ZEND_ENGINE_2_2 -+ dst->__tostring = NULL; ++/* {{{ cache locking macros */ ++#define CACHE_LOCK(cache) { LOCK(cache->header->lock); cache->has_lock = 1; } ++#define CACHE_UNLOCK(cache) { UNLOCK(cache->header->lock); cache->has_lock = 0; } ++#define CACHE_SAFE_LOCK(cache) { if ((++cache->has_lock) == 1) LOCK(cache->header->lock); } ++#define CACHE_SAFE_UNLOCK(cache) { if ((--cache->has_lock) == 0) UNLOCK(cache->header->lock); } ++ ++#if (RDLOCK_AVAILABLE == 1) && defined(HAVE_ATOMIC_OPERATIONS) ++#define USE_READ_LOCKS 1 ++#define CACHE_RDLOCK(cache) { RDLOCK(cache->header->lock); cache->has_lock = 0; } ++#define CACHE_RDUNLOCK(cache) { RDUNLOCK(cache->header->lock); cache->has_lock = 0; } ++#define CACHE_SAFE_INC(cache, obj) { ATOMIC_INC(obj); } ++#define CACHE_SAFE_DEC(cache, obj) { ATOMIC_DEC(obj); } ++#else ++#define USE_READ_LOCKS 0 ++#define CACHE_RDLOCK(cache) { LOCK(cache->header->lock); cache->has_lock = 1; } ++#define CACHE_RDUNLOCK(cache) { UNLOCK(cache->header->lock); cache->has_lock = 0; } ++#define CACHE_SAFE_INC(cache, obj) { CACHE_SAFE_LOCK(cache); obj++; CACHE_SAFE_UNLOCK(cache);} ++#define CACHE_SAFE_DEC(cache, obj) { CACHE_SAFE_LOCK(cache); obj--; CACHE_SAFE_UNLOCK(cache);} +#endif + -+ /* unset function proxies */ -+ dst->serialize_func = NULL; -+ dst->unserialize_func = NULL; -+ -+ my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function, src, dst); -+#endif ++#define CACHE_FAST_INC(cache, obj) { obj++; } ++#define CACHE_FAST_DEC(cache, obj) { obj--; } ++/* }}} */ + -+ if(!(my_copy_hashtable_ex(&dst->default_properties, -+ &src->default_properties, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ allocate,deallocate, -+ (ht_check_copy_fun_t) my_check_copy_default_property, -+ src))) { -+ goto cleanup; -+ } ++/* {{{ struct definition: apc_cache_key_t */ ++#define T apc_cache_t* ++typedef struct apc_cache_t apc_cache_t; /* opaque cache type */ + -+#ifdef ZEND_ENGINE_2 -+ -+ if(!(my_copy_hashtable_ex(&dst->properties_info, -+ &src->properties_info, -+ (ht_copy_fun_t) my_copy_property_info, -+ (ht_free_fun_t) my_free_property_info, -+ 0, -+ allocate, deallocate, -+ (ht_check_copy_fun_t) my_check_copy_property_info, -+ src))) { -+ goto cleanup; -+ } ++typedef union _apc_cache_key_data_t { ++ struct { ++ apc_dev_t device; /* the filesystem device */ ++ apc_ino_t inode; /* the filesystem inode */ ++ } file; ++ struct { ++ const char *identifier; ++ int identifier_len; ++ } user; ++ struct { ++ const char *fullpath; ++ int fullpath_len; ++ } fpfile; ++} apc_cache_key_data_t; + -+#ifdef ZEND_ENGINE_2_2 -+ /* php5.2 introduced a scope attribute for property info */ -+ my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst); -+#endif -+ -+ if(!my_copy_hashtable_ex(&dst->default_static_members, -+ &src->default_static_members, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ allocate, deallocate, -+ (ht_check_copy_fun_t) my_check_copy_static_member, -+ src, -+ &src->default_static_members)) { -+ goto cleanup; -+ } -+ if(src->static_members != &src->default_static_members) -+ { -+ if(!(dst->static_members = my_copy_hashtable_ex(NULL, -+ src->static_members, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ allocate, deallocate, -+ (ht_check_copy_fun_t) my_check_copy_static_member, -+ src, -+ src->static_members))) { -+ goto cleanup; -+ } -+ } -+ else -+ { -+ dst->static_members = &dst->default_static_members; -+ } ++typedef struct apc_cache_key_t apc_cache_key_t; ++struct apc_cache_key_t { ++ apc_cache_key_data_t data; ++ unsigned long h; /* pre-computed hash value */ ++ time_t mtime; /* the mtime of this cached entry */ ++ unsigned char type; ++ unsigned char md5[16]; /* md5 hash of the source file */ ++}; + -+ if(!(my_copy_hashtable(&dst->constants_table, -+ &src->constants_table, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ allocate, deallocate))) { -+ goto cleanup; -+ } + -+ if (src->doc_comment) { -+ if(!(dst->doc_comment = -+ apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) { -+ goto cleanup; -+ } -+ } ++typedef struct apc_keyid_t apc_keyid_t; ++ ++struct apc_keyid_t { ++ unsigned int h; ++ unsigned int keylen; ++ time_t mtime; ++#ifdef ZTS ++ THREAD_T tid; ++#else ++ pid_t pid; +#endif -+ -+ if (src->builtin_functions) { -+ int i, n; ++}; ++/* }}} */ + -+ for (n = 0; src->type == ZEND_INTERNAL_CLASS && src->builtin_functions[n].fname != NULL; n++) {} ++/* {{{ struct definition: apc_cache_entry_t */ ++typedef union _apc_cache_entry_value_t { ++ struct { ++ char *filename; /* absolute path to source file */ ++ zend_op_array* op_array; /* op_array allocated in shared memory */ ++ apc_function_t* functions; /* array of apc_function_t's */ ++ apc_class_t* classes; /* array of apc_class_t's */ ++ long halt_offset; /* value of __COMPILER_HALT_OFFSET__ for the file */ ++ } file; ++ struct { ++ char *info; ++ int info_len; ++ zval *val; ++ unsigned int ttl; ++ } user; ++} apc_cache_entry_value_t; + -+ if(!(dst->builtin_functions = -+ (zend_function_entry*) -+ allocate((n + 1) * sizeof(zend_function_entry)))) { -+ goto cleanup; -+ } ++typedef struct apc_cache_entry_t apc_cache_entry_t; ++struct apc_cache_entry_t { ++ apc_cache_entry_value_t data; ++ unsigned char type; ++ int ref_count; ++ size_t mem_size; ++ apc_pool *pool; ++}; ++/* }}} */ + ++/* ++ * apc_cache_create creates the shared memory compiler cache. This function ++ * should be called just once (ideally in the web server parent process, e.g. ++ * in apache), otherwise you will end up with multiple caches (which won't ++ * necessarily break anything). Returns a pointer to the cache object. ++ * ++ * size_hint is a "hint" at the total number of source files that will be ++ * cached. It determines the physical size of the hash table. Passing 0 for ++ * this argument will use a reasonable default value. ++ * ++ * gc_ttl is the maximum time a cache entry may speed on the garbage ++ * collection list. This is basically a work around for the inherent ++ * unreliability of our reference counting mechanism (see apc_cache_release). ++ * ++ * ttl is the maximum time a cache entry can idle in a slot in case the slot ++ * is needed. This helps in cleaning up the cache and ensuring that entries ++ * hit frequently stay cached and ones not hit very often eventually disappear. ++ */ ++extern T apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC); + -+ for (i = 0; i < n; i++) { -+ if(!my_copy_function_entry(&dst->builtin_functions[i], -+ &src->builtin_functions[i], -+ allocate, deallocate)) { -+ int ii; ++/* ++ * apc_cache_destroy releases any OS resources associated with a cache object. ++ * Under apache, this function can be safely called by the child processes ++ * when they exit. ++ */ ++extern void apc_cache_destroy(T cache TSRMLS_DC); + -+ for(ii=i-1; i>=0; i--) my_destroy_function_entry(&dst->builtin_functions[ii], deallocate); -+ goto cleanup; -+ } -+ } -+ dst->builtin_functions[n].fname = NULL; -+ } ++/* ++ * apc_cache_clear empties a cache. This can safely be called at any time, ++ * even while other server processes are executing cached source files. ++ */ ++extern void apc_cache_clear(T cache TSRMLS_DC); + -+#ifdef ZEND_ENGINE_2 -+ if (src->filename) { -+ if(!(dst->filename = apc_xstrdup(src->filename, allocate))) { -+ goto cleanup; -+ } -+ } -+#endif -+ -+ return dst; ++/* ++ * apc_cache_insert adds an entry to the cache, using a filename as a key. ++ * Internally, the filename is translated to a canonical representation, so ++ * that relative and absolute filenames will map to a single key. Returns ++ * non-zero if the file was successfully inserted, 0 otherwise. If 0 is ++ * returned, the caller must free the cache entry by calling ++ * apc_cache_free_entry (see below). ++ * ++ * key is the value created by apc_cache_make_file_key for file keys. ++ * ++ * value is a cache entry returned by apc_cache_make_entry (see below). ++ */ ++extern int apc_cache_insert(T cache, apc_cache_key_t key, ++ apc_cache_entry_t* value, apc_context_t* ctxt, time_t t TSRMLS_DC); + ++extern int apc_cache_user_insert(T cache, apc_cache_key_t key, ++ apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC); + -+cleanup: -+ if(dst->name) deallocate(dst->name); -+#ifdef ZEND_ENGINE_2 -+ if(dst->doc_comment) deallocate(dst->doc_comment); -+ if(dst->filename) deallocate(dst->filename); -+#else -+ if(dst->refcount) deallocate(dst->refcount); -+#endif -+ -+ if(dst->builtin_functions) deallocate(dst->builtin_functions); -+ if(dst->function_table.arBuckets) my_destroy_hashtable(&dst->function_table, (ht_free_fun_t) my_free_function, deallocate); -+ if(dst->default_properties.arBuckets) my_destroy_hashtable(&dst->default_properties, (ht_free_fun_t) my_free_zval_ptr, deallocate); ++extern 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); + -+#ifdef ZEND_ENGINE_2 -+ if(dst->properties_info.arBuckets) my_destroy_hashtable(&dst->properties_info, (ht_free_fun_t) my_free_property_info, deallocate); -+ if(dst->default_static_members.arBuckets) -+ { -+ my_destroy_hashtable(&dst->default_static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate); -+ } -+ if(dst->static_members && dst->static_members != &(dst->default_static_members)) -+ { -+ my_destroy_hashtable(dst->static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate); -+ deallocate(dst->static_members); -+ } -+ if(dst->constants_table.arBuckets) my_destroy_hashtable(&dst->constants_table, (ht_free_fun_t) my_free_zval_ptr, deallocate); -+#endif -+ if(local_dst_alloc) deallocate(dst); ++/* ++ * apc_cache_find searches for a cache entry by filename, and returns a ++ * pointer to the entry if found, NULL otherwise. ++ * ++ * key is a value created by apc_cache_make_file_key for file keys. ++ */ ++extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t TSRMLS_DC); + -+ return NULL; -+} -+/* }}} */ ++/* ++ * apc_cache_user_find searches for a cache entry by its hashed identifier, ++ * and returns a pointer to the entry if found, NULL otherwise. ++ * ++ */ ++extern apc_cache_entry_t* apc_cache_user_find(T cache, char* strkey, int keylen, time_t t TSRMLS_DC); + -+/* {{{ my_copy_hashtable */ -+static HashTable* my_copy_hashtable_ex(HashTable* dst, -+ HashTable* src, -+ ht_copy_fun_t copy_fn, -+ ht_free_fun_t free_fn, -+ int holds_ptrs, -+ apc_malloc_t allocate, -+ apc_free_t deallocate, -+ ht_check_copy_fun_t check_fn, -+ ...) -+{ -+ Bucket* curr = NULL; -+ Bucket* prev = NULL; -+ Bucket* newp = NULL; -+ int first = 1; -+ int local_dst_alloc = 0; -+ int index = 0; ++/* ++ * apc_cache_user_exists searches for a cache entry by its hashed identifier, ++ * and returns a pointer to the entry if found, NULL otherwise. This is a ++ * quick non-locking version of apc_cache_user_find that does not modify the ++ * shared memory segment in any way. ++ * ++ */ ++extern apc_cache_entry_t* apc_cache_user_exists(T cache, char* strkey, int keylen, time_t t TSRMLS_DC); + -+ assert(src != NULL); ++/* ++ * apc_cache_delete and apc_cache_user_delete finds an entry in the cache and deletes it. ++ */ ++extern int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC); ++extern int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC); + -+ if (!dst) { -+ CHECK(dst = (HashTable*) allocate(sizeof(src[0]))); -+ local_dst_alloc = 1; -+ } ++/* apc_cach_fetch_zval takes a zval in the cache and reconstructs a runtime ++ * zval from it. ++ * ++ */ ++zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC); + -+ memcpy(dst, src, sizeof(src[0])); ++/* ++ * apc_cache_release decrements the reference count associated with a cache ++ * entry. Calling apc_cache_find automatically increments the reference count, ++ * and this function must be called post-execution to return the count to its ++ * original value. Failing to do so will prevent the entry from being ++ * garbage-collected. ++ * ++ * entry is the cache entry whose ref count you want to decrement. ++ */ ++extern void apc_cache_release(T cache, apc_cache_entry_t* entry TSRMLS_DC); + -+ /* allocate buckets for the new hashtable */ -+ if(!(dst->arBuckets = allocate(dst->nTableSize * sizeof(Bucket*)))) { -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; -+ } ++/* ++ * apc_cache_make_file_key creates a key object given a relative or absolute ++ * filename and an optional list of auxillary paths to search. include_path is ++ * searched if the filename cannot be found relative to the current working ++ * directory. ++ * ++ * key points to caller-allocated storage (must not be null). ++ * ++ * filename is the path to the source file. ++ * ++ * include_path is a colon-separated list of directories to search. ++ * ++ * and finally we pass in the current request time so we can avoid ++ * caching files with a current mtime which tends to indicate that ++ * they are still being written to. ++ */ ++extern int apc_cache_make_file_key(apc_cache_key_t* key, ++ const char* filename, ++ const char* include_path, ++ time_t t ++ TSRMLS_DC); + -+ memset(dst->arBuckets, 0, dst->nTableSize * sizeof(Bucket*)); -+ dst->pInternalPointer = NULL; -+ dst->pListHead = NULL; -+ -+ for (curr = src->pListHead; curr != NULL; curr = curr->pListNext) { -+ int n = curr->h % dst->nTableSize; ++/* ++ * apc_cache_make_file_entry creates an apc_cache_entry_t object given a filename ++ * and the compilation results returned by the PHP compiler. ++ */ ++extern 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); + -+ if(check_fn) { -+ va_list args; -+ va_start(args, check_fn); + -+ /* Call the check_fn to see if the current bucket -+ * needs to be copied out -+ */ -+ if(!check_fn(curr, args)) { -+ dst->nNumOfElements--; -+ continue; -+ } ++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_pp, apc_cache_entry_t** cache_entry_pp TSRMLS_DC); + -+ va_end(args); -+ } ++/* ++ * apc_cache_make_user_entry creates an apc_cache_entry_t object given an info string ++ * and the zval to be stored. ++ */ ++extern 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); + -+ /* create a copy of the bucket 'curr' */ -+ if(!(newp = -+ (Bucket*) apc_xmemcpy(curr, -+ sizeof(Bucket) + curr->nKeyLength - 1, -+ allocate))) { -+ goto cleanup; -+ } ++extern int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t); + -+ /* insert 'newp' into the linked list at its hashed index */ -+ if (dst->arBuckets[n]) { -+ newp->pNext = dst->arBuckets[n]; -+ newp->pLast = NULL; -+ newp->pNext->pLast = newp; -+ } -+ else { -+ newp->pNext = newp->pLast = NULL; -+ } ++/* {{{ struct definition: slot_t */ ++typedef struct slot_t slot_t; ++struct slot_t { ++ apc_cache_key_t key; /* slot key */ ++ apc_cache_entry_t* value; /* slot value */ ++ slot_t* next; /* next slot in linked list */ ++ unsigned long num_hits; /* number of hits to this bucket */ ++ time_t creation_time; /* time slot was initialized */ ++ time_t deletion_time; /* time slot was removed from cache */ ++ time_t access_time; /* time slot was last accessed */ ++}; ++/* }}} */ + -+ dst->arBuckets[n] = newp; ++/* {{{ struct definition: cache_header_t ++ Any values that must be shared among processes should go in here. */ ++typedef struct cache_header_t cache_header_t; ++struct cache_header_t { ++ apc_lck_t lock; /* read/write lock (exclusive blocking cache lock) */ ++ apc_lck_t wrlock; /* write lock (non-blocking used to prevent cache slams) */ ++ unsigned long num_hits; /* total successful hits in cache */ ++ unsigned long num_misses; /* total unsuccessful hits in cache */ ++ unsigned long num_inserts; /* total successful inserts in cache */ ++ unsigned long expunges; /* total number of expunges */ ++ slot_t* deleted_list; /* linked list of to-be-deleted slots */ ++ time_t start_time; /* time the above counters were reset */ ++ zend_bool busy; /* Flag to tell clients when we are busy cleaning the cache */ ++ int num_entries; /* Statistic on the number of entries */ ++ size_t mem_size; /* Statistic on the memory size used by this cache */ ++ apc_keyid_t lastkey; /* the key that is being inserted (user cache) */ ++}; ++/* }}} */ + -+ /* copy the bucket data using our 'copy_fn' callback function */ -+ if(!(newp->pData = copy_fn(NULL, curr->pData, allocate, deallocate))) { -+ goto cleanup; -+ } ++typedef void (*apc_expunge_cb_t)(T cache, size_t n TSRMLS_DC); + -+ if (holds_ptrs) { -+ memcpy(&newp->pDataPtr, newp->pData, sizeof(void*)); -+ } -+ else { -+ newp->pDataPtr = NULL; -+ } ++/* {{{ struct definition: apc_cache_t */ ++struct apc_cache_t { ++ void* shmaddr; /* process (local) address of shared cache */ ++ cache_header_t* header; /* cache header (stored in SHM) */ ++ slot_t** slots; /* array of cache slots (stored in SHM) */ ++ int num_slots; /* number of slots in cache */ ++ int gc_ttl; /* maximum time on GC list for a slot */ ++ int ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */ ++ apc_expunge_cb_t expunge_cb; /* cache specific expunge callback to free up sma memory */ ++ uint has_lock; /* flag for possible recursive locks within the same process */ ++}; ++/* }}} */ + -+ /* insert 'newp' into the table-thread linked list */ -+ newp->pListLast = prev; -+ newp->pListNext = NULL; ++extern zval* apc_cache_info(T cache, zend_bool limited TSRMLS_DC); ++extern void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC); ++extern zend_bool apc_cache_busy(apc_cache_t* cache); ++extern zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC); ++extern void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC); ++extern zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t TSRMLS_DC); + -+ if (prev) { -+ prev->pListNext = newp; -+ } ++/* used by apc_rfc1867 to update data in-place - not to be used elsewhere */ + -+ if (first) { -+ dst->pListHead = newp; -+ first = 0; -+ } ++typedef int (*apc_cache_updater_t)(apc_cache_t*, apc_cache_entry_t*, void* data); ++extern int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen, ++ apc_cache_updater_t updater, void* data TSRMLS_DC); + -+ prev = newp; -+ } + -+ dst->pListTail = newp; ++#undef T ++#endif + -+ return dst; -+ -+ cleanup: -+ for(index = 0; index < dst->nTableSize; index++) -+ { -+ curr = dst->arBuckets[index]; -+ while(curr != NULL) -+ { -+ Bucket * tmp = curr; -+ if(curr->pData && free_fn) -+ { -+ free_fn(curr->pData, deallocate); -+ } -+ curr = curr->pNext; -+ deallocate(tmp); -+ } -+ } -+ deallocate(dst->arBuckets); -+ if(local_dst_alloc) deallocate(dst); -+ else dst->arBuckets = NULL; ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_compile.c b/ext/apc/apc_compile.c +--- a/ext/apc/apc_compile.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_compile.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,2164 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | Rasmus Lerdorf | ++ | Arun C. Murthy | ++ | Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ + -+ return NULL; -+} -+/* }}} */ ++ 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. + -+/* {{{ my_copy_static_variables */ -+static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate) -+{ -+ if (src->static_variables == NULL) { -+ return NULL; -+ } ++ All other licensing and usage conditions are those of the PHP Group. + -+ return my_copy_hashtable(NULL, -+ src->static_variables, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ allocate, deallocate); -+} -+/* }}} */ ++ */ + -+/* {{{ apc_copy_zval */ -+zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate) -+{ -+ int local_dst_alloc = 0; -+ assert(src != NULL); ++/* $Id: apc_compile.c 326703 2012-07-19 17:06:12Z rasmus $ */ + -+ if (!dst) { -+ CHECK(dst = (zval*) allocate(sizeof(zval))); -+ local_dst_alloc = 1; -+ } ++#include "apc_compile.h" ++#include "apc_globals.h" ++#include "apc_zend.h" ++#include "apc_php.h" ++#include "apc_string.h" ++#include "ext/standard/php_var.h" ++#include "ext/standard/php_smart_str.h" + -+ dst = my_copy_zval(dst, src, allocate, deallocate); -+ if(!dst) { -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; -+ } -+ return dst; -+} -+/* }}} */ ++typedef void* (*ht_copy_fun_t)(void*, void*, apc_context_t* TSRMLS_DC); ++//typedef void (*ht_free_fun_t)(void*, apc_context_t*); ++typedef int (*ht_check_copy_fun_t)(Bucket*, va_list); + -+#ifdef ZEND_ENGINE_2 -+/* {{{ apc_fixup_op_array_jumps */ -+static void apc_fixup_op_array_jumps(zend_op_array *dst, zend_op_array *src ) -+{ -+ int i; ++typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*); + -+ for (i=0; i < dst->last; ++i) { -+ zend_op *zo = &(dst->opcodes[i]); -+ /*convert opline number to jump address*/ -+ switch (zo->opcode) { -+ case ZEND_JMP: -+ /*Note: if src->opcodes != dst->opcodes then we need to the opline according to src*/ -+ zo->op1.u.jmp_addr = dst->opcodes + (zo->op1.u.jmp_addr - src->opcodes); -+ break; -+ case ZEND_JMPZ: -+ case ZEND_JMPNZ: -+ case ZEND_JMPZ_EX: -+ case ZEND_JMPNZ_EX: -+ zo->op2.u.jmp_addr = dst->opcodes + (zo->op2.u.jmp_addr - src->opcodes); -+ break; -+ default: -+ break; -+ } -+ } -+} -+/* }}} */ ++#define CHECK(p) { if ((p) == NULL) return NULL; } ++ ++/* {{{ internal function declarations */ ++ ++static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_context_t* TSRMLS_DC); ++ ++/* ++ * The "copy" functions perform deep-copies on a particular data structure ++ * (passed as the second argument). They also optionally allocate space for ++ * the destination data structure if the first argument is null. ++ */ ++static zval** my_copy_zval_ptr(zval**, const zval**, apc_context_t* TSRMLS_DC); ++static zval* my_copy_zval(zval*, const zval*, apc_context_t* TSRMLS_DC); ++#ifndef ZEND_ENGINE_2_4 ++static znode* my_copy_znode(znode*, znode*, apc_context_t* TSRMLS_DC); +#endif ++static zend_op* my_copy_zend_op(zend_op*, zend_op*, apc_context_t* TSRMLS_DC); ++static zend_function* my_copy_function(zend_function*, zend_function*, apc_context_t* TSRMLS_DC); ++static zend_function_entry* my_copy_function_entry(zend_function_entry*, const zend_function_entry*, apc_context_t* TSRMLS_DC); ++static zend_class_entry* my_copy_class_entry(zend_class_entry*, zend_class_entry*, apc_context_t* TSRMLS_DC); ++static HashTable* my_copy_hashtable_ex(HashTable*, HashTable* TSRMLS_DC, ht_copy_fun_t, int, apc_context_t*, ht_check_copy_fun_t, ...); ++#define my_copy_hashtable( dst, src, copy_fn, holds_ptr, ctxt) \ ++ my_copy_hashtable_ex(dst, src TSRMLS_CC, copy_fn, holds_ptr, ctxt, NULL) ++static HashTable* my_copy_static_variables(zend_op_array* src, apc_context_t* TSRMLS_DC); ++static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_context_t* TSRMLS_DC); ++static zend_arg_info* my_copy_arg_info_array(zend_arg_info*, const zend_arg_info*, uint, apc_context_t* TSRMLS_DC); ++static zend_arg_info* my_copy_arg_info(zend_arg_info*, const zend_arg_info*, apc_context_t* TSRMLS_DC); + -+/* {{{ apc_copy_op_array */ -+zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC) -+{ -+ int i; -+ int local_dst_alloc = 0; -+ apc_fileinfo_t fileinfo; -+ char canon_path[MAXPATHLEN]; -+ char *fullpath = NULL; -+#ifdef ZEND_ENGINE_2 -+ apc_opflags_t * flags = NULL; ++/* ++ * The "fixup" functions need for ZEND_ENGINE_2 ++ */ ++static void my_fixup_function( Bucket *p, zend_class_entry *src, zend_class_entry *dst ); ++static void my_fixup_hashtable( HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst ); ++/* my_fixup_function_for_execution is the same as my_fixup_function ++ * but named differently for clarity ++ */ ++#define my_fixup_function_for_execution my_fixup_function ++ ++#ifdef ZEND_ENGINE_2_2 ++static void my_fixup_property_info( Bucket *p, zend_class_entry *src, zend_class_entry *dst ); ++#define my_fixup_property_info_for_execution my_fixup_property_info +#endif + -+ assert(src != NULL); ++/* ++ * These functions return "1" if the member/function is ++ * defined/overridden in the 'current' class and not inherited. ++ */ ++static int my_check_copy_function(Bucket* src, va_list args); ++static int my_check_copy_property_info(Bucket* src, va_list args); ++#ifndef ZEND_ENGINE_2_4 ++static int my_check_copy_default_property(Bucket* p, va_list args); ++static int my_check_copy_static_member(Bucket* src, va_list args); ++#endif ++static int my_check_copy_constant(Bucket* src, va_list args); + -+ if (!dst) { -+ CHECK(dst = (zend_op_array*) allocate(sizeof(src[0]))); -+ local_dst_alloc = 1; -+ } ++/* }}} */ + -+ if(APCG(apc_optimize_function)) { -+ APCG(apc_optimize_function)(src TSRMLS_CC); ++/* {{{ apc php serializers */ ++int APC_SERIALIZER_NAME(php) (APC_SERIALIZER_ARGS) ++{ ++ smart_str strbuf = {0}; ++ php_serialize_data_t var_hash; ++ PHP_VAR_SERIALIZE_INIT(var_hash); ++ php_var_serialize(&strbuf, (zval**)&value, &var_hash TSRMLS_CC); ++ PHP_VAR_SERIALIZE_DESTROY(var_hash); ++ if(strbuf.c) { ++ *buf = (unsigned char*)strbuf.c; ++ *buf_len = strbuf.len; ++ smart_str_0(&strbuf); ++ return 1; + } -+ -+ /* start with a bitwise copy of the array */ -+ memcpy(dst, src, sizeof(src[0])); -+ -+ dst->function_name = NULL; -+ dst->filename = NULL; -+ dst->refcount = NULL; -+ dst->opcodes = NULL; -+ dst->brk_cont_array = NULL; -+ dst->static_variables = NULL; -+#ifdef ZEND_ENGINE_2 -+ dst->try_catch_array = NULL; -+ dst->arg_info = NULL; -+ dst->doc_comment = NULL; -+#else -+ dst->arg_types = NULL; -+#endif -+#ifdef ZEND_ENGINE_2_1 -+ dst->vars = NULL; -+#endif ++ return 0; ++} + -+ /* copy the arg types array (if set) */ -+#ifdef ZEND_ENGINE_2 -+ if (src->arg_info) { -+ if(!(dst->arg_info = my_copy_arg_info_array(NULL, -+ src->arg_info, -+ src->num_args, -+ allocate, -+ deallocate))) { -+ goto cleanup; -+ } -+ } -+#else -+ if (src->arg_types) { -+ if(!(dst->arg_types = apc_xmemcpy(src->arg_types, -+ sizeof(src->arg_types[0]) * (src->arg_types[0]+1), -+ allocate))) { -+ goto cleanup; -+ } ++int APC_UNSERIALIZER_NAME(php) (APC_UNSERIALIZER_ARGS) ++{ ++ const unsigned char *tmp = buf; ++ php_unserialize_data_t var_hash; ++ PHP_VAR_UNSERIALIZE_INIT(var_hash); ++ if(!php_var_unserialize(value, &tmp, buf + buf_len, &var_hash TSRMLS_CC)) { ++ PHP_VAR_UNSERIALIZE_DESTROY(var_hash); ++ zval_dtor(*value); ++ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %ld bytes", (long)(tmp - buf), (long)buf_len); ++ (*value)->type = IS_NULL; ++ return 0; + } -+#endif ++ PHP_VAR_UNSERIALIZE_DESTROY(var_hash); ++ return 1; ++} ++/* }}} */ + -+ if (src->function_name) { -+ if(!(dst->function_name = apc_xstrdup(src->function_name, allocate))) { -+ goto cleanup; -+ } -+ } -+ if (src->filename) { -+ if(!(dst->filename = apc_xstrdup(src->filename, allocate))) { -+ goto cleanup; -+ } -+ } ++/* {{{ check_op_array_integrity */ ++#if 0 ++static void check_op_array_integrity(zend_op_array* src) ++{ ++ int i, j; + -+ if(!(dst->refcount = apc_xmemcpy(src->refcount, -+ sizeof(src->refcount[0]), -+ allocate))) { -+ goto cleanup; -+ } ++ /* These sorts of checks really aren't particularly effective, but they ++ * can provide a welcome sanity check when debugging. Just don't enable ++ * for production use! */ + -+ /* deep-copy the opcodes */ -+ if(!(dst->opcodes = (zend_op*) allocate(sizeof(zend_op) * src->last))) { -+ goto cleanup; -+ } ++ assert(src->refcount != NULL); ++ assert(src->opcodes != NULL); ++ assert(src->last > 0); + -+#ifdef ZEND_ENGINE_2 -+ if(APCG(reserved_offset) != -1) { -+ /* Insanity alert: the void* pointer is cast into an apc_opflags_t -+ * struct. apc_zend_init() checks to ensure that it fits in a void* */ -+ flags = (apc_opflags_t*) & (dst->reserved[APCG(reserved_offset)]); -+ memset(flags, 0, sizeof(apc_opflags_t)); -+ /* assert(sizeof(apc_opflags_t) < sizeof(dst->reserved)); */ -+ } -+#endif -+ + for (i = 0; i < src->last; i++) { -+#ifdef ZEND_ENGINE_2 -+ zend_op *zo = &(src->opcodes[i]); -+ /* a lot of files are merely constant arrays with no jumps */ -+ switch (zo->opcode) { -+ case ZEND_JMP: -+ case ZEND_JMPZ: -+ case ZEND_JMPNZ: -+ case ZEND_JMPZ_EX: -+ case ZEND_JMPNZ_EX: -+ if(flags != NULL) { -+ flags->has_jumps = 1; -+ } -+ break; -+#ifdef ZEND_ENGINE_2 -+ /* auto_globals_jit was not in php-4.3.* */ -+ case ZEND_FETCH_R: -+ case ZEND_FETCH_W: -+ case ZEND_FETCH_IS: -+ case ZEND_FETCH_FUNC_ARG: -+ if(PG(auto_globals_jit) && flags != NULL) -+ { -+ /* The fetch is only required if auto_globals_jit=1 */ -+ if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL && -+ zo->op1.op_type == IS_CONST && -+ zo->op1.u.constant.type == IS_STRING) { -+ znode * varname = &zo->op1; -+ if (varname->u.constant.value.str.val[0] == '_') { -+#define SET_IF_AUTOGLOBAL(member) \ -+ if(!strcmp(varname->u.constant.value.str.val, #member)) \ -+ flags->member = 1 /* no ';' here */ -+ SET_IF_AUTOGLOBAL(_GET); -+ else SET_IF_AUTOGLOBAL(_POST); -+ else SET_IF_AUTOGLOBAL(_COOKIE); -+ else SET_IF_AUTOGLOBAL(_SERVER); -+ else SET_IF_AUTOGLOBAL(_ENV); -+ else SET_IF_AUTOGLOBAL(_FILES); -+ else SET_IF_AUTOGLOBAL(_REQUEST); -+ else if(zend_is_auto_global( -+ varname->u.constant.value.str.val, -+ varname->u.constant.value.str.len -+ TSRMLS_CC)) -+ { -+ flags->unknown_global = 1; -+ } -+ } -+ } -+ } -+ break; -+#endif -+ case ZEND_RECV_INIT: -+ if(zo->op2.op_type == IS_CONST && -+ zo->op2.u.constant.type == IS_CONSTANT_ARRAY) { -+ if(flags != NULL) { -+ flags->deep_copy = 1; -+ } -+ } -+ break; -+ default: -+ if((zo->op1.op_type == IS_CONST && -+ zo->op1.u.constant.type == IS_CONSTANT_ARRAY) || -+ (zo->op2.op_type == IS_CONST && -+ zo->op2.u.constant.type == IS_CONSTANT_ARRAY)) { -+ if(flags != NULL) { -+ flags->deep_copy = 1; -+ } -+ } -+ break; -+ } -+#endif -+ if(!(my_copy_zend_op(dst->opcodes+i, src->opcodes+i, allocate, deallocate))) { -+ int ii; -+ for(ii = i-1; ii>=0; ii--) { -+ my_destroy_zend_op(dst->opcodes+ii, deallocate); -+ } -+ goto cleanup; -+ } -+#ifdef ZEND_ENGINE_2 -+/* This code breaks apc's rule#1 - cache what you compile */ -+ if(APCG(fpstat)==0) { -+ if((zo->opcode == ZEND_INCLUDE_OR_EVAL) && -+ (zo->op1.op_type == IS_CONST && zo->op1.u.constant.type == IS_STRING)) { -+ /* constant includes */ -+ if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(&zo->op1.u.constant),len)) { -+ if (apc_search_paths(Z_STRVAL_P(&zo->op1.u.constant), PG(include_path), &fileinfo) == 0) { -+ if((IS_ABSOLUTE_PATH(fileinfo.fullpath, strlen(fileinfo.fullpath)) && (fullpath = fileinfo.fullpath)) -+ || (fullpath = realpath(fileinfo.fullpath, canon_path))) { -+ /* is either an absolute path or it goes through a realpath() */ -+ zend_op *dzo = &(dst->opcodes[i]); -+ deallocate(dzo->op1.u.constant.value.str.val); -+ dzo->op1.u.constant.value.str.len = strlen(fullpath); -+ dzo->op1.u.constant.value.str.val = apc_xstrdup(fullpath, allocate); -+ } -+ } -+ } ++ zend_op* op = &src->opcodes[i]; ++ znode* nodes[] = { &op->result, &op->op1, &op->op2 }; ++ for (j = 0; j < 3; j++) { ++ assert(nodes[j]->op_type == IS_CONST || ++ nodes[j]->op_type == IS_VAR || ++ nodes[j]->op_type == IS_TMP_VAR || ++ nodes[j]->op_type == IS_UNUSED); ++ ++ if (nodes[j]->op_type == IS_CONST) { ++ int type = nodes[j]->u.constant.type; ++ assert(type == IS_RESOURCE || ++ type == IS_BOOL || ++ type == IS_LONG || ++ type == IS_DOUBLE || ++ type == IS_NULL || ++ type == IS_CONSTANT || ++ type == IS_STRING || ++ type == FLAG_IS_BC || ++ type == IS_ARRAY || ++ type == IS_CONSTANT_ARRAY || ++ type == IS_OBJECT); + } + } -+#endif -+ } -+ -+#ifdef ZEND_ENGINE_2 -+ if(flags == NULL || flags->has_jumps) { -+ apc_fixup_op_array_jumps(dst,src); + } ++} +#endif ++/* }}} */ + -+ /* copy the break-continue array */ -+ if (src->brk_cont_array) { -+ if(!(dst->brk_cont_array = -+ apc_xmemcpy(src->brk_cont_array, -+ sizeof(src->brk_cont_array[0]) * src->last_brk_cont, -+ allocate))) { -+ goto cleanup_opcodes; -+ } -+ } ++/* {{{ my_bitwise_copy_function */ ++static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_context_t* ctxt TSRMLS_DC) ++{ ++ apc_pool* pool = ctxt->pool; + -+ /* copy the table of static variables */ -+ if (src->static_variables) { -+ if(!(dst->static_variables = my_copy_static_variables(src, allocate, deallocate))) { -+ goto cleanup_opcodes; -+ } ++ assert(src != NULL); ++ ++ if (!dst) { ++ CHECK(dst = (zend_function*) apc_pool_alloc(pool, sizeof(src[0]))); + } -+ -+#ifdef ZEND_ENGINE_2 -+ if (src->try_catch_array) { -+ if(!(dst->try_catch_array = -+ apc_xmemcpy(src->try_catch_array, -+ sizeof(src->try_catch_array[0]) * src->last_try_catch, -+ allocate))) { -+ goto cleanup_opcodes; -+ } ++ ++ /* We only need to do a bitwise copy */ ++ memcpy(dst, src, sizeof(src[0])); ++ ++ return dst; ++} ++/* }}} */ ++ ++/* {{{ my_copy_zval_ptr */ ++static zval** my_copy_zval_ptr(zval** dst, const zval** src, apc_context_t* ctxt TSRMLS_DC) ++{ ++ zval* dst_new; ++ apc_pool* pool = ctxt->pool; ++ int usegc = (ctxt->copy == APC_COPY_OUT_OPCODE) || (ctxt->copy == APC_COPY_OUT_USER); ++ ++ assert(src != NULL); ++ ++ if (!dst) { ++ CHECK(dst = (zval**) apc_pool_alloc(pool, sizeof(zval*))); + } -+#endif + -+#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */ -+ if (src->vars) { -+ if(!(dst->vars = apc_xmemcpy(src->vars, -+ sizeof(src->vars[0]) * src->last_var, -+ allocate))) { -+ goto cleanup_opcodes; -+ } -+ -+ for(i = 0; i < src->last_var; i++) dst->vars[i].name = NULL; -+ -+ for(i = 0; i < src->last_var; i++) { -+ if(!(dst->vars[i].name = apc_xmemcpy(src->vars[i].name, -+ src->vars[i].name_len + 1, -+ allocate))) { -+ dst->last_var = i; -+ goto cleanup_opcodes; -+ } -+ } ++ if(usegc) { ++ ALLOC_ZVAL(dst[0]); ++ CHECK(dst[0]); ++ } else { ++ CHECK((dst[0] = (zval*) apc_pool_alloc(pool, sizeof(zval)))); + } -+#endif + -+#ifdef ZEND_ENGINE_2 -+ if (src->doc_comment) { -+ if (!(dst->doc_comment -+ = apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) { -+ goto cleanup_opcodes; ++ CHECK((dst_new = my_copy_zval(*dst, *src, ctxt TSRMLS_CC))); ++ ++ if(dst_new != *dst) { ++ if(usegc) { ++ FREE_ZVAL(dst[0]); + } ++ *dst = dst_new; + } -+#endif + + return dst; ++} ++/* }}} */ + -+cleanup_opcodes: -+ if(dst->opcodes) { -+ for(i=0; i < src->last; i++) my_destroy_zend_op(dst->opcodes+i, deallocate); ++/* {{{ my_serialize_object */ ++static zval* my_serialize_object(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) ++{ ++ smart_str buf = {0}; ++ apc_pool* pool = ctxt->pool; ++ apc_serialize_t serialize = APC_SERIALIZER_NAME(php); ++ void *config = NULL; ++ ++ if(APCG(serializer)) { /* TODO: move to ctxt */ ++ serialize = APCG(serializer)->serialize; ++ config = APCG(serializer)->config; + } -+cleanup: -+ if(dst->function_name) deallocate(dst->function_name); -+ if(dst->refcount) deallocate(dst->refcount); -+ if(dst->filename) deallocate(dst->filename); -+#ifdef ZEND_ENGINE_2 -+ if(dst->arg_info) my_free_arg_info_array(dst->arg_info, dst->num_args, deallocate); -+ if(dst->try_catch_array) deallocate(dst->try_catch_array); -+ if(dst->doc_comment) deallocate(dst->doc_comment); -+#else -+ if(dst->arg_types) deallocate(dst->arg_types); -+#endif -+ if(dst->opcodes) deallocate(dst->opcodes); -+ if(dst->brk_cont_array) deallocate(dst->brk_cont_array); -+ if(dst->static_variables) my_free_hashtable(dst->static_variables, (ht_free_fun_t)my_free_zval_ptr, (apc_free_t)deallocate); -+#ifdef ZEND_ENGINE_2_1 -+ if (dst->vars) { -+ for(i=0; i < dst->last_var; i++) { -+ if(dst->vars[i].name) deallocate(dst->vars[i].name); -+ } -+ deallocate(dst->vars); ++ ++ if(serialize((unsigned char**)&buf.c, &buf.len, src, config TSRMLS_CC)) { ++ dst->type = src->type & ~IS_CONSTANT_INDEX; ++ dst->value.str.len = buf.len; ++ CHECK(dst->value.str.val = apc_pmemcpy(buf.c, (buf.len + 1), pool TSRMLS_CC)); + } -+#endif -+ if(local_dst_alloc) deallocate(dst); -+ return NULL; ++ ++ if(buf.c) smart_str_free(&buf); ++ ++ return dst; +} +/* }}} */ + -+/* {{{ apc_copy_new_functions */ -+apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC) ++/* {{{ my_unserialize_object */ ++static zval* my_unserialize_object(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ apc_function_t* array; -+ int new_count; /* number of new functions in table */ -+ int i; -+ -+ new_count = zend_hash_num_elements(CG(function_table)) - old_count; -+ assert(new_count >= 0); -+ -+ CHECK(array = -+ (apc_function_t*) -+ allocate(sizeof(apc_function_t) * (new_count+1))); ++ apc_unserialize_t unserialize = APC_UNSERIALIZER_NAME(php); ++ unsigned char *p = (unsigned char*)Z_STRVAL_P(src); ++ void *config = NULL; + -+ if (new_count == 0) { -+ array[0].function = NULL; -+ return array; ++ if(APCG(serializer)) { /* TODO: move to ctxt */ ++ unserialize = APCG(serializer)->unserialize; ++ config = APCG(serializer)->config; + } -+ -+ /* Skip the first `old_count` functions in the table */ -+ zend_hash_internal_pointer_reset(CG(function_table)); -+ for (i = 0; i < old_count; i++) { -+ zend_hash_move_forward(CG(function_table)); -+ } -+ -+ /* Add the next `new_count` functions to our array */ -+ for (i = 0; i < new_count; i++) { -+ char* key; -+ uint key_size; -+ zend_function* fun; -+ -+ zend_hash_get_current_key_ex(CG(function_table), -+ &key, -+ &key_size, -+ NULL, -+ 0, -+ NULL); -+ -+ zend_hash_get_current_data(CG(function_table), (void**) &fun); + -+ if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) { -+ int ii; -+ for(ii=i-1; ii>=0; ii--) { -+ deallocate(array[ii].name); -+ my_free_function(array[ii].function, deallocate); -+ } -+ deallocate(array); -+ return NULL; -+ } -+ array[i].name_len = (int) key_size-1; -+ if(!(array[i].function = my_copy_function(NULL, fun, allocate, deallocate))) { -+ int ii; -+ deallocate(array[i].name); -+ for(ii=i-1; ii>=0; ii--) { -+ deallocate(array[ii].name); -+ my_free_function(array[ii].function, deallocate); -+ } -+ deallocate(array); -+ return NULL; -+ } -+ zend_hash_move_forward(CG(function_table)); ++ if(unserialize(&dst, p, Z_STRLEN_P(src), config TSRMLS_CC)) { ++ return dst; ++ } else { ++ zval_dtor(dst); ++ dst->type = IS_NULL; + } -+ -+ array[i].function = NULL; -+ return array; ++ return dst; +} +/* }}} */ + -+/* {{{ apc_copy_new_classes */ -+apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC) -+{ -+ apc_class_t* array; -+ int new_count; /* number of new classes in table */ -+ int i; -+ -+ new_count = zend_hash_num_elements(CG(class_table)) - old_count; -+ assert(new_count >= 0); -+ -+ CHECK(array = -+ (apc_class_t*) -+ allocate(sizeof(apc_class_t)*(new_count+1))); -+ -+ if (new_count == 0) { -+ array[0].class_entry = NULL; -+ return array; -+ } -+ -+ /* Skip the first `old_count` classes in the table */ -+ zend_hash_internal_pointer_reset(CG(class_table)); -+ for (i = 0; i < old_count; i++) { -+ zend_hash_move_forward(CG(class_table)); ++static char *apc_string_pmemcpy(char *str, size_t len, apc_pool* pool TSRMLS_DC) ++{ ++#ifdef ZEND_ENGINE_2_4 ++#ifndef ZTS ++ if (pool->type != APC_UNPOOL) { ++ char * ret = (char*)apc_new_interned_string((const char*)str, len TSRMLS_CC); ++ if (ret) { ++ return ret; ++ } + } -+ -+ /* Add the next `new_count` classes to our array */ -+ for (i = 0; i < new_count; i++) { -+ char* key; -+ uint key_size; -+ zend_class_entry* elem = NULL; -+ -+ array[i].class_entry = NULL; -+ -+ zend_hash_get_current_key_ex(CG(class_table), -+ &key, -+ &key_size, -+ NULL, -+ 0, -+ NULL); -+ -+ zend_hash_get_current_data(CG(class_table), (void**) &elem); -+ -+ -+#ifdef ZEND_ENGINE_2 -+ elem = *((zend_class_entry**)elem); +#endif -+ -+ if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) { -+ int ii; ++#endif ++ return apc_pmemcpy(str, len, pool TSRMLS_CC); ++} + -+ for(ii=i-1; ii>=0; ii--) { -+ deallocate(array[ii].name); -+ my_destroy_class_entry(array[ii].class_entry, deallocate); -+ deallocate(array[ii].class_entry); -+ } -+ deallocate(array); -+ return NULL; -+ } -+ array[i].name_len = (int) key_size-1; -+ if(!(array[i].class_entry = my_copy_class_entry(NULL, elem, allocate, deallocate))) { -+ int ii; -+ -+ deallocate(array[i].name); -+ for(ii=i-1; ii>=0; ii--) { -+ deallocate(array[ii].name); -+ my_destroy_class_entry(array[ii].class_entry, deallocate); -+ deallocate(array[ii].class_entry); -+ } -+ deallocate(array); -+ return NULL; -+ } ++/* {{{ my_copy_zval */ ++static APC_HOTSPOT zval* my_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) ++{ ++ zval **tmp; ++ apc_pool* pool = ctxt->pool; + -+ /* -+ * If the class has a pointer to its parent class, save the parent -+ * name so that we can enable compile-time inheritance when we reload -+ * the child class; otherwise, set the parent name to null and scan -+ * the op_array to determine if this class inherits from some base -+ * class at execution-time. -+ */ ++ assert(dst != NULL); ++ assert(src != NULL); + -+ if (elem->parent) { -+ if(!(array[i].parent_name = -+ apc_xstrdup(elem->parent->name, allocate))) { -+ int ii; -+ -+ for(ii=i; ii>=0; ii--) { -+ deallocate(array[ii].name); -+ my_destroy_class_entry(array[ii].class_entry, deallocate); -+ deallocate(array[ii].class_entry); -+ if(ii==i) continue; -+ if(array[ii].parent_name) deallocate(array[ii].parent_name); -+ } -+ deallocate(array); -+ return NULL; ++ memcpy(dst, src, sizeof(src[0])); ++ ++ if(APCG(copied_zvals).nTableSize) { ++ if(zend_hash_index_find(&APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) { ++ if(Z_ISREF_P((zval*)src)) { ++ Z_SET_ISREF_PP(tmp); + } -+ array[i].is_derived = 1; -+ } -+ else { -+ array[i].parent_name = NULL; -+ array[i].is_derived = is_derived_class(op_array, key, key_size); ++ Z_ADDREF_PP(tmp); ++ return *tmp; + } + -+ zend_hash_move_forward(CG(class_table)); ++ zend_hash_index_update(&APCG(copied_zvals), (ulong)src, (void**)&dst, sizeof(zval*), NULL); + } + -+ array[i].class_entry = NULL; -+ return array; -+} -+/* }}} */ + -+/* {{{ my_destroy_zval_ptr */ -+static void my_destroy_zval_ptr(zval** src, apc_free_t deallocate) -+{ -+ assert(src != NULL); -+ if(my_destroy_zval(src[0], deallocate) == SUCCESS) { -+ deallocate(src[0]); ++ if(ctxt->copy == APC_COPY_OUT_USER || ctxt->copy == APC_COPY_IN_USER) { ++ /* deep copies are refcount(1), but moved up for recursive ++ * arrays, which end up being add_ref'd during its copy. */ ++ Z_SET_REFCOUNT_P(dst, 1); ++ Z_UNSET_ISREF_P(dst); ++ } else { ++ /* code uses refcount=2 for consts */ ++ Z_SET_REFCOUNT_P(dst, Z_REFCOUNT_P((zval*)src)); ++ Z_SET_ISREF_TO_P(dst, Z_ISREF_P((zval*)src)); + } -+} -+/* }}} */ -+ -+/* {{{ my_destroy_zval */ -+static int my_destroy_zval(zval* src, apc_free_t deallocate) -+{ -+ zval **tmp; -+ TSRMLS_FETCH(); + -+ switch (src->type & ~IS_CONSTANT_INDEX) { ++ switch (src->type & IS_CONSTANT_TYPE_MASK) { + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: @@ -3799,1975 +3834,1841 @@ Index: php-5.2.3/ext/apc/apc_compile.c + + case IS_CONSTANT: + case IS_STRING: -+#ifndef ZEND_ENGINE_2 -+ case FLAG_IS_BC: -+#endif -+ deallocate(src->value.str.val); -+ break; -+ -+ case IS_ARRAY: -+ -+ /* Maintain a list of zvals we've copied to properly handle recursive structures */ -+ if(APCG(copied_zvals)) { -+ if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) { -+ (*tmp)->refcount--; -+ return FAILURE; -+ } -+ zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&src, sizeof(zval*), NULL); ++ if (src->value.str.val) { ++ CHECK(dst->value.str.val = apc_string_pmemcpy(src->value.str.val, ++ src->value.str.len+1, ++ pool TSRMLS_CC)); + } -+ /* fall through */ ++ break; + ++ case IS_ARRAY: + case IS_CONSTANT_ARRAY: -+ my_free_hashtable(src->value.ht, -+ (ht_free_fun_t) my_free_zval_ptr, -+ deallocate); -+ break; ++ if(APCG(serializer) == NULL || ++ ctxt->copy == APC_COPY_IN_OPCODE || ctxt->copy == APC_COPY_OUT_OPCODE) { ++ ++ CHECK(dst->value.ht = ++ my_copy_hashtable(NULL, ++ src->value.ht, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt)); ++ break; ++ } else { ++ /* fall through to object case */ ++ } + + case IS_OBJECT: -+#ifndef ZEND_ENGINE_2 -+ my_destroy_class_entry(src->value.obj.ce, deallocate); -+ deallocate(src->value.obj.ce); -+ my_free_hashtable(src->value.obj.properties, -+ (ht_free_fun_t) my_free_zval_ptr, -+ deallocate); -+#endif ++ ++ dst->type = IS_NULL; ++ if(ctxt->copy == APC_COPY_IN_USER) { ++ dst = my_serialize_object(dst, src, ctxt TSRMLS_CC); ++ } else if(ctxt->copy == APC_COPY_OUT_USER) { ++ dst = my_unserialize_object(dst, src, ctxt TSRMLS_CC); ++ } + break; + + default: + assert(0); + } + -+ return SUCCESS; ++ return dst; ++} ++/* }}} */ ++ ++#ifdef ZEND_ENGINE_2_4 ++/* {{{ my_copy_znode */ ++static void my_check_znode(zend_uchar op_type, apc_context_t* ctxt TSRMLS_DC) ++{ ++ assert(op_type == IS_CONST || ++ op_type == IS_VAR || ++ op_type == IS_CV || ++ op_type == IS_TMP_VAR || ++ op_type == IS_UNUSED); +} +/* }}} */ + -+/* {{{ my_destroy_znode */ -+static void my_destroy_znode(znode* src, apc_free_t deallocate) ++/* {{{ my_copy_zend_op */ ++static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_context_t* ctxt TSRMLS_DC) ++{ ++ assert(dst != NULL); ++ assert(src != NULL); ++ ++ memcpy(dst, src, sizeof(src[0])); ++ ++ my_check_znode(dst->result_type & ~EXT_TYPE_UNUSED, ctxt TSRMLS_CC); ++ my_check_znode(dst->op1_type, ctxt TSRMLS_CC); ++ my_check_znode(dst->op2_type, ctxt TSRMLS_CC); ++ ++ return dst; ++} ++/* }}} */ ++#else ++/* {{{ my_copy_znode */ ++static znode* my_copy_znode(znode* dst, znode* src, apc_context_t* ctxt TSRMLS_DC) +{ ++ assert(dst != NULL); ++ assert(src != NULL); ++ ++ memcpy(dst, src, sizeof(src[0])); ++ ++#ifdef IS_CV ++ assert(dst ->op_type == IS_CONST || ++ dst ->op_type == IS_VAR || ++ dst ->op_type == IS_CV || ++ dst ->op_type == IS_TMP_VAR || ++ dst ->op_type == IS_UNUSED); ++#else ++ assert(dst ->op_type == IS_CONST || ++ dst ->op_type == IS_VAR || ++ dst ->op_type == IS_TMP_VAR || ++ dst ->op_type == IS_UNUSED); ++#endif ++ + if (src->op_type == IS_CONST) { -+ my_destroy_zval(&src->u.constant, deallocate); ++ if(!my_copy_zval(&dst->u.constant, &src->u.constant, ctxt TSRMLS_CC)) { ++ return NULL; ++ } + } ++ ++ return dst; +} +/* }}} */ + -+/* {{{ my_destroy_zend_op */ -+static void my_destroy_zend_op(zend_op* src, apc_free_t deallocate) ++/* {{{ my_copy_zend_op */ ++static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ my_destroy_znode(&src->result, deallocate); -+ my_destroy_znode(&src->op1, deallocate); -+ my_destroy_znode(&src->op2, deallocate); ++ assert(dst != NULL); ++ assert(src != NULL); ++ ++ memcpy(dst, src, sizeof(src[0])); ++ ++ CHECK(my_copy_znode(&dst->result, &src->result, ctxt TSRMLS_CC)); ++ CHECK(my_copy_znode(&dst->op1, &src->op1, ctxt TSRMLS_CC)); ++ CHECK(my_copy_znode(&dst->op2, &src->op2, ctxt TSRMLS_CC)); ++ ++ return dst; +} +/* }}} */ ++#endif + -+/* {{{ my_destroy_function */ -+static void my_destroy_function(zend_function* src, apc_free_t deallocate) ++/* {{{ my_copy_function */ ++static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_context_t* ctxt TSRMLS_DC) +{ + assert(src != NULL); + ++ CHECK(dst = my_bitwise_copy_function(dst, src, ctxt TSRMLS_CC)); ++ + switch (src->type) { + case ZEND_INTERNAL_FUNCTION: + case ZEND_OVERLOADED_FUNCTION: ++ /* shallow copy because op_array is internal */ ++ dst->op_array = src->op_array; + break; -+ ++ + case ZEND_USER_FUNCTION: + case ZEND_EVAL_CODE: -+ my_destroy_op_array(&src->op_array, deallocate); ++ CHECK(apc_copy_op_array(&dst->op_array, ++ &src->op_array, ++ ctxt TSRMLS_CC)); + break; + + default: + assert(0); + } -+} -+/* }}} */ ++ /* ++ * op_array bitwise copying overwrites what ever you modified ++ * before apc_copy_op_array - which is why this code is outside ++ * my_bitwise_copy_function. ++ */ + -+/* {{{ my_destroy_function_entry */ -+static void my_destroy_function_entry(zend_function_entry* src, apc_free_t deallocate) -+{ -+ assert(src != NULL); ++ /* zend_do_inheritance will re-look this up, because the pointers ++ * in prototype are from a function table of another class. It just ++ * helps if that one is from EG(class_table). ++ */ ++ dst->common.prototype = NULL; + -+ deallocate(src->fname); -+#ifdef ZEND_ENGINE_2 -+ if (src->arg_info) { -+ my_free_arg_info_array(src->arg_info, src->num_args, deallocate); -+ } -+#else -+ if (src->func_arg_types) { -+ deallocate(src->func_arg_types); -+ } -+#endif -+} -+/* }}} */ ++ /* once a method is marked as ZEND_ACC_IMPLEMENTED_ABSTRACT then you ++ * have to carry around a prototype. Thankfully zend_do_inheritance ++ * sets this properly as well ++ */ ++ dst->common.fn_flags = src->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT); + -+#ifdef ZEND_ENGINE_2 -+/* {{{ my_destroy_property_info*/ -+static void my_destroy_property_info(zend_property_info* src, apc_free_t deallocate) -+{ -+ assert(src != NULL); + -+ deallocate(src->name); -+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0 -+ if(src->doc_comment) deallocate(src->doc_comment); -+#endif ++ return dst; +} +/* }}} */ + -+/* {{{ my_destroy_arg_info_array */ -+static void my_destroy_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate) ++/* {{{ my_copy_function_entry */ ++static zend_function_entry* my_copy_function_entry(zend_function_entry* dst, const zend_function_entry* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ int i = 0; -+ + assert(src != NULL); + -+ for(i=0; i < num_args; i++) { -+ my_destroy_arg_info(&src[i], deallocate); ++ if (!dst) { ++ CHECK(dst = (zend_function_entry*) apc_pool_alloc(ctxt->pool, sizeof(src[0]))); + } -+} -+/* }}} */ + -+/* {{{ my_destroy_arg_info */ -+static void my_destroy_arg_info(zend_arg_info* src, apc_free_t deallocate) -+{ -+ assert(src != NULL); ++ /* Start with a bitwise copy */ ++ memcpy(dst, src, sizeof(src[0])); ++ ++ dst->fname = NULL; ++ dst->arg_info = NULL; ++ ++ if (src->fname) { ++ CHECK((dst->fname = apc_pstrdup(src->fname, ctxt->pool TSRMLS_CC))); ++ } + -+ deallocate(src->name); -+ deallocate(src->class_name); ++ if (src->arg_info) { ++ CHECK((dst->arg_info = my_copy_arg_info_array(NULL, ++ src->arg_info, ++ src->num_args, ++ ctxt TSRMLS_CC))); ++ } ++ ++ return dst; +} +/* }}} */ -+#endif + -+/* {{{ my_destroy_class_entry */ -+static void my_destroy_class_entry(zend_class_entry* src, apc_free_t deallocate) ++/* {{{ my_copy_property_info */ ++static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ uint i; ++ apc_pool* pool = ctxt->pool; + + assert(src != NULL); + -+ deallocate(src->name); -+#ifndef ZEND_ENGINE_2 -+ deallocate(src->refcount); -+#else -+ if(src->doc_comment) deallocate(src->doc_comment); -+ if(src->filename) deallocate(src->filename); -+#endif -+ -+ my_destroy_hashtable(&src->function_table, -+ (ht_free_fun_t) my_free_function, -+ deallocate); ++ if (!dst) { ++ CHECK(dst = (zend_property_info*) apc_pool_alloc(pool, sizeof(*src))); ++ } + -+ my_destroy_hashtable(&src->default_properties, -+ (ht_free_fun_t) my_free_zval_ptr, -+ deallocate); ++ /* Start with a bitwise copy */ ++ memcpy(dst, src, sizeof(*src)); + -+#ifdef ZEND_ENGINE_2 -+ my_destroy_hashtable(&src->properties_info, -+ (ht_free_fun_t) my_free_property_info, -+ deallocate); -+ if(src->static_members) -+ { -+ my_destroy_hashtable(src->static_members, -+ (ht_free_fun_t) my_free_zval_ptr, -+ deallocate); -+ if(src->static_members != &(src->default_static_members)) -+ { -+ deallocate(src->static_members); -+ } ++ dst->name = NULL; ++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0 ++ dst->doc_comment = NULL; ++#endif ++ ++ if (src->name) { ++ /* private members are stored inside property_info as a mangled ++ * string of the form: ++ * \0\0\0 ++ */ ++ CHECK((dst->name = apc_string_pmemcpy(src->name, src->name_length+1, pool TSRMLS_CC))); + } + -+ my_destroy_hashtable(&src->constants_table, -+ (ht_free_fun_t) my_free_zval_ptr, -+ deallocate); ++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0 ++ if (src->doc_comment) { ++ CHECK((dst->doc_comment = apc_pmemcpy(src->doc_comment, (src->doc_comment_len + 1), pool TSRMLS_CC))); ++ } +#endif + -+ if (src->builtin_functions) { -+ for (i = 0; src->builtin_functions[i].fname != NULL; i++) { -+ my_destroy_function_entry(&src->builtin_functions[i], deallocate); -+ } -+ deallocate(src->builtin_functions); -+ } ++ return dst; +} +/* }}} */ + -+/* {{{ my_destroy_hashtable */ -+static void my_destroy_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate) ++/* {{{ my_copy_property_info_for_execution */ ++static zend_property_info* my_copy_property_info_for_execution(zend_property_info* dst, zend_property_info* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ int i; -+ + assert(src != NULL); + -+ for (i = 0; i < src->nTableSize; i++) { -+ Bucket* p = src->arBuckets[i]; -+ while (p != NULL) { -+ Bucket* q = p; -+ p = p->pNext; -+ free_fn(q->pData, deallocate); -+ deallocate(q); -+ } ++ if (!dst) { ++ CHECK(dst = (zend_property_info*) apc_pool_alloc(ctxt->pool, sizeof(*src))); + } + -+ deallocate(src->arBuckets); ++ /* We need only a shallow copy */ ++ memcpy(dst, src, sizeof(*src)); ++ ++ return dst; +} +/* }}} */ + -+/* {{{ my_destroy_op_array */ -+static void my_destroy_op_array(zend_op_array* src, apc_free_t deallocate) ++/* {{{ my_copy_arg_info_array */ ++static zend_arg_info* my_copy_arg_info_array(zend_arg_info* dst, const zend_arg_info* src, uint num_args, apc_context_t* ctxt TSRMLS_DC) +{ -+ int i; ++ uint i = 0; + -+ assert(src != NULL); + -+#ifdef ZEND_ENGINE_2 -+ if (src->arg_info) { -+ my_free_arg_info_array(src->arg_info, src->num_args, deallocate); -+ } -+#else -+ if (src->arg_types) { -+ deallocate(src->arg_types); ++ if (!dst) { ++ CHECK(dst = (zend_arg_info*) apc_pool_alloc(ctxt->pool, (sizeof(*src) * num_args))); + } -+#endif + -+ deallocate(src->function_name); -+ deallocate(src->filename); -+ deallocate(src->refcount); -+ -+ for (i = 0; i < src->last; i++) { -+ my_destroy_zend_op(src->opcodes + i, deallocate); -+ } -+ deallocate(src->opcodes); ++ /* Start with a bitwise copy */ ++ memcpy(dst, src, sizeof(*src)*num_args); + -+ if (src->brk_cont_array) { -+ deallocate(src->brk_cont_array); ++ for(i=0; i < num_args; i++) { ++ CHECK((my_copy_arg_info( &dst[i], &src[i], ctxt TSRMLS_CC))); + } + -+ if (src->static_variables) { -+ my_free_hashtable(src->static_variables, -+ (ht_free_fun_t) my_free_zval_ptr, -+ deallocate); -+ } -+ -+#ifdef ZEND_ENGINE_2_1 -+ if (src->vars) { -+ for(i=0; i < src->last_var; i++) { -+ if(src->vars[i].name) deallocate(src->vars[i].name); -+ } -+ deallocate(src->vars); -+ } -+#endif -+#ifdef ZEND_ENGINE_2 -+ if(src->try_catch_array) { -+ deallocate(src->try_catch_array); -+ } -+ if (src->doc_comment) { -+ deallocate(src->doc_comment); -+ } -+#endif ++ return dst; +} +/* }}} */ + -+/* {{{ my_free_zval_ptr */ -+static void my_free_zval_ptr(zval** src, apc_free_t deallocate) ++/* {{{ my_copy_arg_info */ ++static zend_arg_info* my_copy_arg_info(zend_arg_info* dst, const zend_arg_info* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ my_destroy_zval_ptr(src, deallocate); -+ deallocate(src); -+} -+/* }}} */ ++ apc_pool* pool = ctxt->pool; + -+#ifdef ZEND_ENGINE_2 -+/* {{{ my_free_property_info */ -+static void my_free_property_info(zend_property_info* src, apc_free_t deallocate) -+{ -+ my_destroy_property_info(src, deallocate); -+ deallocate(src); -+} -+/* }}} */ ++ assert(src != NULL); + -+/* {{{ my_free_arg_info_array */ -+static void my_free_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate) -+{ -+ my_destroy_arg_info_array(src, num_args, deallocate); -+ deallocate(src); -+} -+/* }}} */ ++ if (!dst) { ++ CHECK(dst = (zend_arg_info*) apc_pool_alloc(pool, sizeof(*src))); ++ } + -+/* {{{ my_free_arg_info */ -+static void my_free_arg_info(zend_arg_info* src, apc_free_t deallocate) -+{ -+ my_destroy_arg_info(src, deallocate); -+ deallocate(src); -+} -+/* }}} */ -+#endif ++ /* Start with a bitwise copy */ ++ memcpy(dst, src, sizeof(*src)); + -+/* {{{ my_free_function */ -+static void my_free_function(zend_function* src, apc_free_t deallocate) -+{ -+ my_destroy_function(src, deallocate); -+ deallocate(src); -+} -+/* }}} */ ++ dst->name = NULL; ++ dst->class_name = NULL; + -+/* {{{ my_free_hashtable */ -+static void my_free_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate) -+{ -+ my_destroy_hashtable(src, free_fn, deallocate); -+ deallocate(src); -+} -+/* }}} */ ++ if (src->name) { ++ CHECK((dst->name = apc_string_pmemcpy((char *) src->name, src->name_len+1, pool TSRMLS_CC))); ++ } + -+/* {{{ apc_free_op_array */ -+void apc_free_op_array(zend_op_array* src, apc_free_t deallocate) -+{ -+ if (src != NULL) { -+ my_destroy_op_array(src, deallocate); -+ deallocate(src); ++ if (src->class_name) { ++ CHECK((dst->class_name = apc_string_pmemcpy((char *) src->class_name, src->class_name_len+1, pool TSRMLS_CC))); + } ++ ++ return dst; +} +/* }}} */ + -+/* {{{ apc_free_functions */ -+void apc_free_functions(apc_function_t* src, apc_free_t deallocate) ++/* {{{ apc_copy_class_entry */ ++zend_class_entry* apc_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ int i; -+ -+ if (src != NULL) { -+ for (i = 0; src[i].function != NULL; i++) { -+ deallocate(src[i].name); -+ my_destroy_function(src[i].function, deallocate); -+ deallocate(src[i].function); -+ } -+ deallocate(src); -+ } ++ return my_copy_class_entry(dst, src, ctxt TSRMLS_CC); +} -+/* }}} */ + -+/* {{{ apc_free_classes */ -+void apc_free_classes(apc_class_t* src, apc_free_t deallocate) ++/* {{{ my_copy_class_entry */ ++static zend_class_entry* my_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ int i; ++ int i = 0; ++ apc_pool* pool = ctxt->pool; + -+ if (src != NULL) { -+ for (i = 0; src[i].class_entry != NULL; i++) { -+ deallocate(src[i].name); -+ deallocate(src[i].parent_name); -+ my_destroy_class_entry(src[i].class_entry, deallocate); -+ deallocate(src[i].class_entry); -+ } -+ deallocate(src); -+ } -+} -+/* }}} */ ++ assert(src != NULL); + -+/* {{{ apc_free_zval */ -+void apc_free_zval(zval* src, apc_free_t deallocate) -+{ -+ if (src != NULL) { -+ if(my_destroy_zval(src, deallocate) == SUCCESS) { -+ deallocate(src); -+ } ++ if (!dst) { ++ CHECK(dst = (zend_class_entry*) apc_pool_alloc(pool, sizeof(*src))); + } -+} -+/* }}} */ + ++ /* Start with a bitwise copy */ ++ memcpy(dst, src, sizeof(*src)); + -+/* Used only by my_prepare_op_array_for_execution */ -+#define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION() \ -+ /* The fetch is only required if auto_globals_jit=1 */ \ -+ if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL && \ -+ zo->op1.op_type == IS_CONST && \ -+ zo->op1.u.constant.type == IS_STRING && \ -+ zo->op1.u.constant.value.str.val[0] == '_') { \ -+ \ -+ znode* varname = &zo->op1; \ -+ (void)zend_is_auto_global(varname->u.constant.value.str.val, \ -+ varname->u.constant.value.str.len \ -+ TSRMLS_CC); \ -+ } \ ++ dst->name = NULL; ++ memset(&dst->function_table, 0, sizeof(dst->function_table)); ++ ZEND_CE_DOC_COMMENT(dst) = NULL; ++ ZEND_CE_FILENAME(dst) = NULL; ++ memset(&dst->properties_info, 0, sizeof(dst->properties_info)); ++ memset(&dst->constants_table, 0, sizeof(dst->constants_table)); + -+/* {{{ my_prepare_op_array_for_execution */ -+static int my_prepare_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC) -+{ -+ /* combine my_fetch_global_vars and my_copy_data_exceptions. -+ * - Pre-fetch superglobals which would've been pre-fetched in parse phase. -+ * - If the opcode stream contain mutable data, ensure a copy. -+ * - Fixup array jumps in the same loop. -+ */ -+ int i=src->last; -+ zend_op *zo; -+ zend_op *dzo; -+#ifdef ZEND_ENGINE_2 -+ apc_opflags_t * flags = APCG(reserved_offset) != -1 ? -+ (apc_opflags_t*) & (src->reserved[APCG(reserved_offset)]) : NULL; -+ int needcopy = flags ? flags->deep_copy : 1; -+ /* auto_globals_jit was not in php4 */ -+ int do_prepare_fetch_global = PG(auto_globals_jit) && (flags == NULL || flags->unknown_global); ++ if (src->name) { ++ CHECK((dst->name = apc_pstrdup(src->name, pool TSRMLS_CC))); ++ } + -+#define FETCH_AUTOGLOBAL(member) do { \ -+ if(flags && flags->member == 1) { \ -+ zend_is_auto_global(#member,\ -+ (sizeof(#member) - 1)\ -+ TSRMLS_CC);\ -+ } \ -+}while(0); -+ -+ FETCH_AUTOGLOBAL(_GET); -+ FETCH_AUTOGLOBAL(_POST); -+ FETCH_AUTOGLOBAL(_COOKIE); -+ FETCH_AUTOGLOBAL(_SERVER); -+ FETCH_AUTOGLOBAL(_ENV); -+ FETCH_AUTOGLOBAL(_FILES); -+ FETCH_AUTOGLOBAL(_REQUEST); ++ if(!(my_copy_hashtable_ex(&dst->function_table, ++ &src->function_table TSRMLS_CC, ++ (ht_copy_fun_t) my_copy_function, ++ 0, ++ ctxt, ++ (ht_check_copy_fun_t) my_check_copy_function, ++ src))) { ++ return NULL; ++ } + -+#else -+ int needcopy = 0; -+ int do_prepare_fetch_global = 0; -+ int j = 0; ++ /* the interfaces are populated at runtime using ADD_INTERFACE */ ++ dst->interfaces = NULL; + -+ for(j = 0; j < src->last; j++) { -+ zo = &src->opcodes[j]; -+ -+ if( ((zo->op1.op_type == IS_CONST && -+ zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) || -+ ((zo->op2.op_type == IS_CONST && -+ zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) { -+ needcopy = 1; ++ /* the current count includes inherited interfaces as well, ++ the real dynamic ones are the first which are zero'd ++ out in zend_do_end_class_declaration */ ++ for(i = 0 ; (uint)i < src->num_interfaces ; i++) { ++ if(src->interfaces[i]) ++ { ++ dst->num_interfaces = i; ++ break; + } + } ++ ++ /* these will either be set inside my_fixup_hashtable or ++ * they will be copied out from parent inside zend_do_inheritance ++ */ ++ dst->parent = NULL; ++ dst->constructor = NULL; ++ dst->destructor = NULL; ++ dst->clone = NULL; ++ dst->__get = NULL; ++ dst->__set = NULL; ++ dst->__unset = NULL; ++ dst->__isset = NULL; ++ dst->__call = NULL; ++#ifdef ZEND_ENGINE_2_2 ++ dst->__tostring = NULL; ++#endif ++#ifdef ZEND_ENGINE_2_3 ++ dst->__callstatic = NULL; +#endif -+ -+ if(needcopy) { + -+ dst->opcodes = (zend_op*) apc_xmemcpy(src->opcodes, -+ sizeof(zend_op) * src->last, -+ apc_php_malloc); -+ zo = src->opcodes; -+ dzo = dst->opcodes; -+ while(i > 0) { ++ /* unset function proxies */ ++ dst->serialize_func = NULL; ++ dst->unserialize_func = NULL; + -+ if( ((zo->op1.op_type == IS_CONST && -+ zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) || -+ ((zo->op2.op_type == IS_CONST && -+ zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) { ++ my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function, src, dst); + -+ if(!(my_copy_zend_op(dzo, zo, apc_php_malloc, apc_php_free))) { -+ assert(0); /* emalloc failed or a bad constant array */ -+ } -+ } -+ -+#ifdef ZEND_ENGINE_2 -+ switch(zo->opcode) { -+ case ZEND_JMP: -+ dzo->op1.u.jmp_addr = dst->opcodes + -+ (zo->op1.u.jmp_addr - src->opcodes); -+ break; -+ case ZEND_JMPZ: -+ case ZEND_JMPNZ: -+ case ZEND_JMPZ_EX: -+ case ZEND_JMPNZ_EX: -+ dzo->op2.u.jmp_addr = dst->opcodes + -+ (zo->op2.u.jmp_addr - src->opcodes); -+ break; -+ case ZEND_FETCH_R: -+ case ZEND_FETCH_W: -+ case ZEND_FETCH_IS: -+ case ZEND_FETCH_FUNC_ARG: -+ if(do_prepare_fetch_global) -+ { -+ APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION(); -+ } -+ break; -+ default: -+ break; ++#ifdef ZEND_ENGINE_2_4 ++ dst->default_properties_count = src->default_properties_count; ++ if (src->default_properties_count) { ++ CHECK(dst->default_properties_table = (zval**) apc_pool_alloc(pool, (sizeof(zval*) * src->default_properties_count))); ++ for (i = 0; i < src->default_properties_count; i++) { ++ if (src->default_properties_table[i]) { ++ my_copy_zval_ptr(&dst->default_properties_table[i], (const zval**)&src->default_properties_table[i], ctxt TSRMLS_CC); ++ } else { ++ dst->default_properties_table[i] = NULL; + } -+#endif -+ i--; -+ zo++; -+ dzo++; + } -+#ifdef ZEND_ENGINE_2 -+ } else { /* !needcopy */ -+ /* The fetch is only required if auto_globals_jit=1 */ -+ if(do_prepare_fetch_global) -+ { -+ zo = src->opcodes; -+ while(i > 0) { ++ } else { ++ dst->default_properties_table = NULL; ++ } ++#else ++ memset(&dst->default_properties, 0, sizeof(dst->default_properties)); ++ CHECK((my_copy_hashtable_ex(&dst->default_properties, ++ &src->default_properties TSRMLS_CC, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt, ++ (ht_check_copy_fun_t) my_check_copy_default_property, ++ src))); ++#endif + -+ if(zo->opcode == ZEND_FETCH_R || -+ zo->opcode == ZEND_FETCH_W || -+ zo->opcode == ZEND_FETCH_IS || -+ zo->opcode == ZEND_FETCH_FUNC_ARG -+ ) { -+ APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION(); -+ } ++ CHECK((my_copy_hashtable_ex(&dst->properties_info, ++ &src->properties_info TSRMLS_CC, ++ (ht_copy_fun_t) my_copy_property_info, ++ 0, ++ ctxt, ++ (ht_check_copy_fun_t) my_check_copy_property_info, ++ src))); + -+ i--; -+ zo++; -+ } -+ } ++#ifdef ZEND_ENGINE_2_2 ++ /* php5.2 introduced a scope attribute for property info */ ++ my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst); +#endif ++ ++#ifdef ZEND_ENGINE_2_4 ++ dst->default_static_members_count = src->default_static_members_count; ++ ++ if (src->default_static_members_count) { ++ CHECK(dst->default_static_members_table = (zval**) apc_pool_alloc(pool, (sizeof(zval*) * src->default_static_members_count))); ++ for (i = 0; i < src->default_static_members_count; i++) { ++ if (src->default_static_members_table[i]) { ++ my_copy_zval_ptr(&dst->default_static_members_table[i], (const zval**)&src->default_static_members_table[i], ctxt TSRMLS_CC); ++ } else { ++ dst->default_static_members_table[i] = NULL; ++ } ++ } ++ } else { ++ dst->default_static_members_table = NULL; + } -+ return 1; -+} -+/* }}} */ ++ dst->static_members_table = dst->default_static_members_table; ++#else ++ memset(&dst->default_static_members, 0, sizeof(dst->default_static_members)); ++ dst->static_members = NULL; ++ CHECK(my_copy_hashtable_ex(&dst->default_static_members, ++ &src->default_static_members TSRMLS_CC, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt, ++ (ht_check_copy_fun_t) my_check_copy_static_member, ++ src, ++ &src->default_static_members)); + -+/* {{{ apc_copy_op_array_for_execution */ -+zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC) -+{ -+ if(dst == NULL) { -+ dst = (zend_op_array*) emalloc(sizeof(src[0])); ++ if(src->static_members != &src->default_static_members) ++ { ++ CHECK((dst->static_members = my_copy_hashtable_ex(NULL, ++ src->static_members TSRMLS_CC, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt, ++ (ht_check_copy_fun_t) my_check_copy_static_member, ++ src, ++ src->static_members))); + } -+ memcpy(dst, src, sizeof(src[0])); -+ dst->static_variables = my_copy_static_variables(src, apc_php_malloc, apc_php_free); ++ else ++ { ++ dst->static_members = &dst->default_static_members; ++ } ++#endif + -+ dst->refcount = apc_xmemcpy(src->refcount, -+ sizeof(src->refcount[0]), -+ apc_php_malloc); -+ -+ my_prepare_op_array_for_execution(dst,src TSRMLS_CC); ++ CHECK((my_copy_hashtable_ex(&dst->constants_table, ++ &src->constants_table TSRMLS_CC, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt, ++ (ht_check_copy_fun_t) my_check_copy_constant, ++ src))); + -+ return dst; -+} -+/* }}} */ ++ if (src->type == ZEND_USER_CLASS && ZEND_CE_DOC_COMMENT(src)) { ++ CHECK(ZEND_CE_DOC_COMMENT(dst) = ++ apc_pmemcpy(ZEND_CE_DOC_COMMENT(src), (ZEND_CE_DOC_COMMENT_LEN(src) + 1), pool TSRMLS_CC)); ++ } + -+/* {{{ apc_copy_function_for_execution */ -+zend_function* apc_copy_function_for_execution(zend_function* src) -+{ -+ zend_function* dst; -+ TSRMLS_FETCH(); ++ if (src->type == ZEND_INTERNAL_CLASS && ZEND_CE_BUILTIN_FUNCTIONS(src)) { ++ int n; ++ ++ for (n = 0; src->type == ZEND_INTERNAL_CLASS && ZEND_CE_BUILTIN_FUNCTIONS(src)[n].fname != NULL; n++) {} ++ ++ CHECK((ZEND_CE_BUILTIN_FUNCTIONS(dst) = ++ (zend_function_entry*) apc_pool_alloc(pool, ((n + 1) * sizeof(zend_function_entry))))); ++ ++ for (i = 0; i < n; i++) { ++ CHECK(my_copy_function_entry((zend_function_entry*)(&ZEND_CE_BUILTIN_FUNCTIONS(dst)[i]), ++ &ZEND_CE_BUILTIN_FUNCTIONS(src)[i], ++ ctxt TSRMLS_CC)); ++ } ++ *(char**)&(ZEND_CE_BUILTIN_FUNCTIONS(dst)[n].fname) = NULL; ++ } ++ ++ if (src->type == ZEND_USER_CLASS && ZEND_CE_FILENAME(src)) { ++ CHECK((ZEND_CE_FILENAME(dst) = apc_pstrdup(ZEND_CE_FILENAME(src), pool TSRMLS_CC))); ++ } + -+ dst = (zend_function*) emalloc(sizeof(src[0])); -+ memcpy(dst, src, sizeof(src[0])); -+ apc_copy_op_array_for_execution(&(dst->op_array), &(src->op_array) TSRMLS_CC); + return dst; +} +/* }}} */ + -+/* {{{ apc_copy_function_for_execution_ex */ -+zend_function* apc_copy_function_for_execution_ex(void *dummy, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate) ++/* {{{ my_copy_hashtable_ex */ ++static APC_HOTSPOT HashTable* my_copy_hashtable_ex(HashTable* dst, ++ HashTable* src TSRMLS_DC, ++ ht_copy_fun_t copy_fn, ++ int holds_ptrs, ++ apc_context_t* ctxt, ++ ht_check_copy_fun_t check_fn, ++ ...) +{ -+ if(src->type==ZEND_INTERNAL_FUNCTION || src->type==ZEND_OVERLOADED_FUNCTION) return src; -+ return apc_copy_function_for_execution(src); -+} -+/* }}} */ ++ Bucket* curr = NULL; ++ Bucket* prev = NULL; ++ Bucket* newp = NULL; ++ int first = 1; ++ apc_pool* pool = ctxt->pool; + -+/* {{{ apc_copy_class_entry_for_execution */ -+zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived) -+{ -+ zend_class_entry* dst = (zend_class_entry*) emalloc(sizeof(src[0])); -+ memcpy(dst, src, sizeof(src[0])); ++ assert(src != NULL); + -+#ifdef ZEND_ENGINE_2 -+ if(src->num_interfaces) -+ { -+ /* These are slots to be populated later by ADD_INTERFACE insns */ -+ dst->interfaces = apc_php_malloc( -+ sizeof(zend_class_entry*) * src->num_interfaces); -+ memset(dst->interfaces, 0, -+ sizeof(zend_class_entry*) * src->num_interfaces); -+ } -+ else -+ { -+ /* assert(dst->interfaces == NULL); */ ++ if (!dst) { ++ CHECK(dst = (HashTable*) apc_pool_alloc(pool, sizeof(src[0]))); + } -+#endif + -+#ifndef ZEND_ENGINE_2 -+ dst->refcount = apc_xmemcpy(src->refcount, -+ sizeof(src->refcount[0]), -+ apc_php_malloc); -+#endif ++ memcpy(dst, src, sizeof(src[0])); + -+ /* Deep-copy the class properties, because they will be modified */ ++ /* allocate buckets for the new hashtable */ ++ CHECK((dst->arBuckets = apc_pool_alloc(pool, (dst->nTableSize * sizeof(Bucket*))))); + -+ my_copy_hashtable(&dst->default_properties, -+ &src->default_properties, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ apc_php_malloc, apc_php_free); ++ memset(dst->arBuckets, 0, dst->nTableSize * sizeof(Bucket*)); ++ dst->pInternalPointer = NULL; ++ dst->pListHead = NULL; + -+ /* For derived classes, we must also copy the function hashtable (although -+ * we can merely bitwise copy the functions it contains) */ ++ for (curr = src->pListHead; curr != NULL; curr = curr->pListNext) { ++ int n = curr->h % dst->nTableSize; + -+ my_copy_hashtable(&dst->function_table, -+ &src->function_table, -+ (ht_copy_fun_t) apc_copy_function_for_execution_ex, -+ NULL, -+ 0, -+ apc_php_malloc, apc_php_free); -+#ifdef ZEND_ENGINE_2 -+ my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function_for_execution, src, dst); ++ if(check_fn) { ++ va_list args; ++ va_start(args, check_fn); + -+ /* zend_do_inheritance merges properties_info. -+ * Need only shallow copying as it doesn't hold the pointers. -+ */ -+ my_copy_hashtable(&dst->properties_info, -+ &src->properties_info, -+ (ht_copy_fun_t) my_copy_property_info_for_execution, -+ NULL, -+ 0, -+ apc_php_malloc, apc_php_free); ++ /* Call the check_fn to see if the current bucket ++ * needs to be copied out ++ */ ++ if(!check_fn(curr, args)) { ++ dst->nNumOfElements--; ++ va_end(args); ++ continue; ++ } + -+#ifdef ZEND_ENGINE_2_2 -+ /* php5.2 introduced a scope attribute for property info */ -+ my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst); ++ va_end(args); ++ } ++ ++ /* create a copy of the bucket 'curr' */ ++#ifdef ZEND_ENGINE_2_4 ++ if (!curr->nKeyLength) { ++ CHECK((newp = (Bucket*) apc_pmemcpy(curr, sizeof(Bucket), pool TSRMLS_CC))); ++ } else if (IS_INTERNED(curr->arKey)) { ++ CHECK((newp = (Bucket*) apc_pmemcpy(curr, sizeof(Bucket), pool TSRMLS_CC))); ++#ifndef ZTS ++ } else if (pool->type != APC_UNPOOL) { ++ char *arKey; ++ ++ CHECK((newp = (Bucket*) apc_pmemcpy(curr, sizeof(Bucket), pool TSRMLS_CC))); ++ arKey = apc_new_interned_string(curr->arKey, curr->nKeyLength TSRMLS_CC); ++ if (!arKey) { ++ CHECK((newp->arKey = (char*) apc_pmemcpy(curr->arKey, curr->nKeyLength, pool TSRMLS_CC))); ++ } else { ++ newp->arKey = arKey; ++ } ++#endif ++ } else { ++ CHECK((newp = (Bucket*) apc_pmemcpy(curr, sizeof(Bucket), pool TSRMLS_CC))); ++ CHECK((newp->arKey = (char*) apc_pmemcpy(curr->arKey, curr->nKeyLength, pool TSRMLS_CC))); ++ } ++#else ++ CHECK((newp = (Bucket*) apc_pmemcpy(curr, ++ (sizeof(Bucket) + curr->nKeyLength - 1), ++ pool TSRMLS_CC))); +#endif + -+ /* if inheritance results in a hash_del, it might result in -+ * a pefree() of the pointers here. Deep copying required. -+ */ ++ /* insert 'newp' into the linked list at its hashed index */ ++ if (dst->arBuckets[n]) { ++ newp->pNext = dst->arBuckets[n]; ++ newp->pLast = NULL; ++ newp->pNext->pLast = newp; ++ } ++ else { ++ newp->pNext = newp->pLast = NULL; ++ } + -+ my_copy_hashtable(&dst->constants_table, -+ &src->constants_table, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ NULL, -+ 1, -+ apc_php_malloc, apc_php_free); ++ dst->arBuckets[n] = newp; + -+ my_copy_hashtable(&dst->default_static_members, -+ &src->default_static_members, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ apc_php_malloc, apc_php_free); ++ /* copy the bucket data using our 'copy_fn' callback function */ ++ CHECK((newp->pData = copy_fn(NULL, curr->pData, ctxt TSRMLS_CC))); + -+ if(src->static_members != &(src->default_static_members)) -+ { -+ dst->static_members = my_copy_hashtable(NULL, -+ src->static_members, -+ (ht_copy_fun_t) my_copy_zval_ptr, -+ (ht_free_fun_t) my_free_zval_ptr, -+ 1, -+ apc_php_malloc, apc_php_free); -+ } -+ else -+ { -+ dst->static_members = &(dst->default_static_members); ++ if (holds_ptrs) { ++ memcpy(&newp->pDataPtr, newp->pData, sizeof(void*)); ++ } ++ else { ++ newp->pDataPtr = NULL; ++ } ++ ++ /* insert 'newp' into the table-thread linked list */ ++ newp->pListLast = prev; ++ newp->pListNext = NULL; ++ ++ if (prev) { ++ prev->pListNext = newp; ++ } ++ ++ if (first) { ++ dst->pListHead = newp; ++ first = 0; ++ } ++ ++ prev = newp; + } + -+#endif ++ dst->pListTail = newp; ++ ++ zend_hash_internal_pointer_reset(dst); + + return dst; +} +/* }}} */ + -+/* {{{ apc_free_class_entry_after_execution */ -+void apc_free_class_entry_after_execution(zend_class_entry* src) ++/* {{{ my_copy_static_variables */ ++static HashTable* my_copy_static_variables(zend_op_array* src, apc_context_t* ctxt TSRMLS_DC) +{ -+#ifdef ZEND_ENGINE_2 -+ if(src->num_interfaces > 0 && src->interfaces) { -+ apc_php_free(src->interfaces); -+ src->interfaces = NULL; -+ src->num_interfaces = 0; ++ if (src->static_variables == NULL) { ++ return NULL; + } -+ /* my_destroy_hashtable() does not play nice with refcounts */ + -+ zend_hash_clean(&src->default_static_members); -+ if(src->static_members != &(src->default_static_members)) -+ { -+ zend_hash_destroy(src->static_members); -+ apc_php_free(src->static_members); -+ src->static_members = NULL; -+ } -+ else -+ { -+ src->static_members = NULL; ++ return my_copy_hashtable(NULL, ++ src->static_variables, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt); ++} ++/* }}} */ ++ ++/* {{{ apc_copy_zval */ ++zval* apc_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC) ++{ ++ apc_pool* pool = ctxt->pool; ++ int usegc = (ctxt->copy == APC_COPY_OUT_OPCODE) || (ctxt->copy == APC_COPY_OUT_USER); ++ ++ assert(src != NULL); ++ ++ if (!dst) { ++ if(usegc) { ++ ALLOC_ZVAL(dst); ++ CHECK(dst); ++ } else { ++ CHECK(dst = (zval*) apc_pool_alloc(pool, sizeof(zval))); ++ } + } -+ zend_hash_clean(&src->default_properties); -+ zend_hash_clean(&src->constants_table); -+#endif + -+ /* TODO: more cleanup */ ++ CHECK(dst = my_copy_zval(dst, src, ctxt TSRMLS_CC)); ++ return dst; +} +/* }}} */ + -+#ifdef ZEND_ENGINE_2 -+ -+/* {{{ my_fixup_function */ -+static void my_fixup_function(Bucket *p, zend_class_entry *src, zend_class_entry *dst) ++/* {{{ apc_fixup_op_array_jumps */ ++static void apc_fixup_op_array_jumps(zend_op_array *dst, zend_op_array *src ) +{ -+ zend_function* zf = p->pData; -+ -+ #define SET_IF_SAME_NAME(member) \ -+ do { \ -+ if(src->member && !strcmp(zf->common.function_name, src->member->common.function_name)) { \ -+ dst->member = zf; \ -+ } \ -+ } \ -+ while(0) ++ uint i; + -+ if(zf->common.scope == src) -+ { -+ -+ /* Fixing up the default functions for objects here since -+ * we need to compare with the newly allocated functions -+ * -+ * caveat: a sub-class method can have the same name as the -+ * parent's constructor and create problems. -+ */ -+ -+ if(zf->common.fn_flags & ZEND_ACC_CTOR) dst->constructor = zf; -+ else if(zf->common.fn_flags & ZEND_ACC_DTOR) dst->destructor = zf; -+ else if(zf->common.fn_flags & ZEND_ACC_CLONE) dst->clone = zf; -+ else -+ { -+ SET_IF_SAME_NAME(__get); -+ SET_IF_SAME_NAME(__set); -+ SET_IF_SAME_NAME(__unset); -+ SET_IF_SAME_NAME(__isset); -+ SET_IF_SAME_NAME(__call); -+#ifdef ZEND_ENGINE_2_2 -+ SET_IF_SAME_NAME(__tostring); ++ for (i=0; i < dst->last; ++i) { ++ zend_op *zo = &(dst->opcodes[i]); ++ /*convert opline number to jump address*/ ++ switch (zo->opcode) { ++#ifdef ZEND_ENGINE_2_3 ++ case ZEND_GOTO: +#endif -+ } -+ zf->common.scope = dst; -+ } -+ else -+ { -+ /* no other function should reach here */ -+ assert(0); -+ } -+ -+ #undef SET_IF_SAME_NAME -+} -+/* }}} */ -+ -+#ifdef ZEND_ENGINE_2_2 -+/* {{{ my_fixup_property_info */ -+static void my_fixup_property_info(Bucket *p, zend_class_entry *src, zend_class_entry *dst) -+{ -+ zend_property_info* property_info = (zend_property_info*)p->pData; -+ -+ if(property_info->ce == src) -+ { -+ property_info->ce = dst; -+ } -+ else -+ { -+ assert(0); /* should never happen */ -+ } -+} -+/* }}} */ ++ case ZEND_JMP: ++ /*Note: if src->opcodes != dst->opcodes then we need to the opline according to src*/ ++#ifdef ZEND_ENGINE_2_4 ++ zo->op1.jmp_addr = dst->opcodes + (zo->op1.jmp_addr - src->opcodes); ++#else ++ zo->op1.u.jmp_addr = dst->opcodes + (zo->op1.u.jmp_addr - src->opcodes); +#endif -+ -+/* {{{ my_fixup_hashtable */ -+static void my_fixup_hashtable(HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst) -+{ -+ Bucket *p; -+ -+ uint i; -+ -+ for (i = 0; i < ht->nTableSize; i++) { -+ if(!ht->arBuckets) break; -+ p = ht->arBuckets[i]; -+ while (p != NULL) { -+ fixup(p, src, dst); -+ p = p->pNext; -+ } -+ } -+} -+/* }}} */ -+ ++ break; ++ case ZEND_JMPZ: ++ case ZEND_JMPNZ: ++ case ZEND_JMPZ_EX: ++ case ZEND_JMPNZ_EX: ++#ifdef ZEND_ENGINE_2_3 ++ case ZEND_JMP_SET: +#endif -+ -+/* {{{ my_check_copy_function */ -+static int my_check_copy_function(Bucket* p, va_list args) -+{ -+ zend_class_entry* src = va_arg(args, zend_class_entry*); -+ zend_function* zf = (zend_function*)p->pData; -+#ifndef ZEND_ENGINE_2 -+ zend_class_entry* parent = src->parent; -+ zend_function* parent_fn = NULL; ++#ifdef ZEND_ENGINE_2_4 ++ case ZEND_JMP_SET_VAR: +#endif -+ -+#ifdef ZEND_ENGINE_2 -+ return (zf->common.scope == src); ++#ifdef ZEND_ENGINE_2_4 ++ zo->op2.jmp_addr = dst->opcodes + (zo->op2.jmp_addr - src->opcodes); +#else -+ if (parent && -+ zend_hash_quick_find(&parent->function_table, p->arKey, -+ p->nKeyLength, p->h, (void **) &parent_fn)==SUCCESS) { -+ -+ if((parent_fn && zf) && -+ (parent_fn->op_array.refcount == zf->op_array.refcount)) -+ { -+ return 0; ++ zo->op2.u.jmp_addr = dst->opcodes + (zo->op2.u.jmp_addr - src->opcodes); ++#endif ++ break; ++ default: ++ break; + } + } -+ return 1; -+#endif +} +/* }}} */ + -+/* {{{ my_check_copy_default_property */ -+static int my_check_copy_default_property(Bucket* p, va_list args) ++/* {{{ apc_copy_op_array */ ++zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ zend_class_entry* src = va_arg(args, zend_class_entry*); -+ zend_class_entry* parent = src->parent; -+ zval ** child_prop = (zval**)p->pData; -+ zval ** parent_prop = NULL; ++ int i; ++ apc_fileinfo_t *fileinfo = NULL; ++ char canon_path[MAXPATHLEN]; ++ char *fullpath = NULL; ++ apc_opflags_t * flags = NULL; ++ apc_pool* pool = ctxt->pool; + -+ if (parent && -+ zend_hash_quick_find(&parent->default_properties, p->arKey, -+ p->nKeyLength, p->h, (void **) &parent_prop)==SUCCESS) { ++ assert(src != NULL); + -+ if((parent_prop && child_prop) && (*parent_prop) == (*child_prop)) -+ { -+ return 0; -+ } ++ if (!dst) { ++ CHECK(dst = (zend_op_array*) apc_pool_alloc(pool, sizeof(src[0]))); + } -+ -+ /* possibly not in the parent */ -+ return 1; -+} -+/* }}} */ + -+#ifdef ZEND_ENGINE_2 ++ if(APCG(apc_optimize_function)) { ++ APCG(apc_optimize_function)(src TSRMLS_CC); ++ } + -+/* {{{ my_check_copy_property_info */ -+static int my_check_copy_property_info(Bucket* p, va_list args) -+{ -+ zend_class_entry* src = va_arg(args, zend_class_entry*); -+ zend_class_entry* parent = src->parent; -+ zend_property_info* child_info = (zend_property_info*)p->pData; -+ zend_property_info* parent_info = NULL; ++ /* start with a bitwise copy of the array */ ++ memcpy(dst, src, sizeof(src[0])); + -+#ifdef ZEND_ENGINE_2_2 -+ /* so much easier */ -+ return (child_info->ce == src); ++ dst->function_name = NULL; ++ dst->filename = NULL; ++ dst->refcount = NULL; ++ dst->opcodes = NULL; ++ dst->brk_cont_array = NULL; ++ dst->static_variables = NULL; ++ dst->try_catch_array = NULL; ++ dst->arg_info = NULL; ++ dst->doc_comment = NULL; ++#ifdef ZEND_ENGINE_2_1 ++ dst->vars = NULL; +#endif + -+ if (parent && -+ zend_hash_quick_find(&parent->properties_info, p->arKey, p->nKeyLength, -+ p->h, (void **) &parent_info)==SUCCESS) { -+ if(parent_info->flags & ZEND_ACC_PRIVATE) -+ { -+ return 1; -+ } -+ if((parent_info->flags & ZEND_ACC_PPP_MASK) != -+ (child_info->flags & ZEND_ACC_PPP_MASK)) -+ { -+ /* TODO: figure out whether ACC_CHANGED is more appropriate -+ * here */ -+ return 1; -+ } -+ return 0; ++ /* copy the arg types array (if set) */ ++ if (src->arg_info) { ++ CHECK(dst->arg_info = my_copy_arg_info_array(NULL, ++ src->arg_info, ++ src->num_args, ++ ctxt TSRMLS_CC)); + } -+ -+ /* property doesn't exist in parent, copy into cached child */ -+ return 1; -+} -+/* }}} */ -+ -+/* {{{ my_check_copy_static_member */ -+static int my_check_copy_static_member(Bucket* p, va_list args) -+{ -+ zend_class_entry* src = va_arg(args, zend_class_entry*); -+ HashTable * ht = va_arg(args, HashTable*); -+ zend_class_entry* parent = src->parent; -+ HashTable * parent_ht = NULL; -+ char * member_name; -+ char * class_name = NULL; -+ -+ zend_property_info *parent_info = NULL; -+ zend_property_info *child_info = NULL; -+ zval ** parent_prop = NULL; -+ zval ** child_prop = (zval**)(p->pData); + -+ if(!parent) { -+ return 1; ++ if (src->function_name) { ++ CHECK(dst->function_name = apc_pstrdup(src->function_name, pool TSRMLS_CC)); ++ } ++ if (src->filename) { ++ CHECK(dst->filename = apc_pstrdup(src->filename, pool TSRMLS_CC)); + } + -+ /* these do not need free'ing */ -+#ifdef ZEND_ENGINE_2_2 -+ zend_unmangle_property_name(p->arKey, p->nKeyLength-1, &class_name, &member_name); -+#else -+ zend_unmangle_property_name(p->arKey, &class_name, &member_name); -+#endif -+ -+ /* please refer do_inherit_property_access_check in zend_compile.c -+ * to understand why we lookup in properties_info. -+ */ -+ if((zend_hash_find(&parent->properties_info, member_name, -+ strlen(member_name)+1, (void**)&parent_info) == SUCCESS) -+ && -+ (zend_hash_find(&src->properties_info, member_name, -+ strlen(member_name)+1, (void**)&child_info) == SUCCESS)) -+ { -+ if(child_info->flags & ZEND_ACC_STATIC && -+ (parent_info->flags & ZEND_ACC_PROTECTED && -+ child_info->flags & ZEND_ACC_PUBLIC)) -+ { -+ /* Do not copy into static_members. zend_do_inheritance -+ * will automatically insert a NULL value. -+ * TODO: decrement refcount or fixup when copying out for exec ? -+ */ -+ return 0; -+ } -+ if(ht == &(src->default_static_members)) -+ { -+ parent_ht = &parent->default_static_members; -+ } -+ else -+ { -+ parent_ht = parent->static_members; -+ } -+ -+ if(zend_hash_quick_find(parent_ht, p->arKey, -+ p->nKeyLength, p->h, (void**)&parent_prop) == SUCCESS) -+ { -+ /* they point to the same zval */ -+ if(*parent_prop == *child_prop) -+ { -+ return 0; -+ } ++ CHECK(dst->refcount = apc_pmemcpy(src->refcount, ++ sizeof(src->refcount[0]), ++ pool TSRMLS_CC)); ++ ++#ifdef ZEND_ENGINE_2_4 ++ if (src->literals) { ++ zend_literal *p, *q, *end; ++ ++ q = src->literals; ++ p = dst->literals = (zend_literal*) apc_pool_alloc(pool, (sizeof(zend_literal) * src->last_literal)); ++ end = p + src->last_literal; ++ while (p < end) { ++ *p = *q; ++ my_copy_zval(&p->constant, &q->constant, ctxt TSRMLS_CC); ++ p++; ++ q++; + } + } -+ -+ return 1; -+} -+/* }}} */ +#endif + -+/* {{{ apc_register_optimizer(apc_optimize_function_t optimizer) -+ * register a optimizer callback function, returns the previous callback -+ */ -+apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC) { -+ apc_optimize_function_t old_optimizer = APCG(apc_optimize_function); -+ APCG(apc_optimize_function) = optimizer; -+ return old_optimizer; -+} -+ -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_compile.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_compile.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,134 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | Arun C. Murthy | -+ | Gopal Vijayaraghavan | -+ +----------------------------------------------------------------------+ ++ /* deep-copy the opcodes */ ++ CHECK(dst->opcodes = (zend_op*) apc_pool_alloc(pool, (sizeof(zend_op) * src->last))); + -+ 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. ++ if(apc_reserved_offset != -1) { ++ /* Insanity alert: the void* pointer is cast into an apc_opflags_t ++ * struct. apc_zend_init() checks to ensure that it fits in a void* */ ++ flags = (apc_opflags_t*) & (dst->reserved[apc_reserved_offset]); ++ memset(flags, 0, sizeof(apc_opflags_t)); ++ /* assert(sizeof(apc_opflags_t) <= sizeof(dst->reserved)); */ ++ } + -+ */ ++ for (i = 0; (uint) i < src->last; i++) { ++ zend_op *zo = &(src->opcodes[i]); ++ /* a lot of files are merely constant arrays with no jumps */ ++ switch (zo->opcode) { ++#ifdef ZEND_ENGINE_2_3 ++ case ZEND_GOTO: ++#endif ++ case ZEND_JMP: ++ case ZEND_JMPZ: ++ case ZEND_JMPNZ: ++ case ZEND_JMPZ_EX: ++ case ZEND_JMPNZ_EX: ++#ifdef ZEND_ENGINE_2_3 ++ case ZEND_JMP_SET: ++#endif ++#ifdef ZEND_ENGINE_2_4 ++ case ZEND_JMP_SET_VAR: ++#endif ++ if(flags != NULL) { ++ flags->has_jumps = 1; ++ } ++ break; ++ /* auto_globals_jit was not in php-4.3.* */ ++ case ZEND_FETCH_R: ++ case ZEND_FETCH_W: ++ case ZEND_FETCH_IS: ++ case ZEND_FETCH_FUNC_ARG: ++ case ZEND_FETCH_RW: ++ case ZEND_FETCH_UNSET: ++ if(PG(auto_globals_jit) && flags != NULL) ++ { ++ /* The fetch is only required if auto_globals_jit=1 */ ++#ifdef ZEND_ENGINE_2_4 ++ if((zo->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL && ++ zo->op1_type == IS_CONST && ++ Z_TYPE_P(zo->op1.zv) == IS_STRING) { ++ if (Z_STRVAL_P(zo->op1.zv)[0] == '_') { ++# define SET_IF_AUTOGLOBAL(member) \ ++ if(!strcmp(Z_STRVAL_P(zo->op1.zv), #member)) \ ++ flags->member = 1 /* no ';' here */ ++#else ++ if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL && ++ zo->op1.op_type == IS_CONST && ++ zo->op1.u.constant.type == IS_STRING) { ++ znode * varname = &zo->op1; ++ if (varname->u.constant.value.str.val[0] == '_') { ++# define SET_IF_AUTOGLOBAL(member) \ ++ if(!strcmp(varname->u.constant.value.str.val, #member)) \ ++ flags->member = 1 /* no ';' here */ ++#endif ++ SET_IF_AUTOGLOBAL(_GET); ++ else SET_IF_AUTOGLOBAL(_POST); ++ else SET_IF_AUTOGLOBAL(_COOKIE); ++ else SET_IF_AUTOGLOBAL(_SERVER); ++ else SET_IF_AUTOGLOBAL(_ENV); ++ else SET_IF_AUTOGLOBAL(_FILES); ++ else SET_IF_AUTOGLOBAL(_REQUEST); ++ else SET_IF_AUTOGLOBAL(_SESSION); ++#ifdef ZEND_ENGINE_2_4 ++ else if(zend_is_auto_global( ++ Z_STRVAL_P(zo->op1.zv), ++ Z_STRLEN_P(zo->op1.zv) ++ TSRMLS_CC)) ++#else ++ else if(zend_is_auto_global( ++ varname->u.constant.value.str.val, ++ varname->u.constant.value.str.len ++ TSRMLS_CC)) ++#endif ++ { ++ flags->unknown_global = 1; ++ } ++#ifdef ZEND_ENGINE_2_4 ++ } else SET_IF_AUTOGLOBAL(GLOBALS); ++#else ++ } ++#endif ++ } ++ } ++ break; ++ case ZEND_RECV_INIT: ++#ifdef ZEND_ENGINE_2_4 ++ if(zo->op2_type == IS_CONST && ++ Z_TYPE_P(zo->op2.zv) == IS_CONSTANT_ARRAY) { ++#else ++ if(zo->op2.op_type == IS_CONST && ++ zo->op2.u.constant.type == IS_CONSTANT_ARRAY) { ++#endif ++ if(flags != NULL) { ++ flags->deep_copy = 1; ++ } ++ } ++ break; ++ default: ++#ifdef ZEND_ENGINE_2_4 ++ if((zo->op1_type == IS_CONST && ++ Z_TYPE_P(zo->op1.zv) == IS_CONSTANT_ARRAY) || ++ (zo->op2_type == IS_CONST && ++ Z_TYPE_P(zo->op2.zv) == IS_CONSTANT_ARRAY)) { ++#else ++ if((zo->op1.op_type == IS_CONST && ++ zo->op1.u.constant.type == IS_CONSTANT_ARRAY) || ++ (zo->op2.op_type == IS_CONST && ++ zo->op2.u.constant.type == IS_CONSTANT_ARRAY)) { ++#endif ++ if(flags != NULL) { ++ flags->deep_copy = 1; ++ } ++ } ++ break; ++ } + -+/* $Id: apc_compile.h,v 3.19 2007/03/08 22:03:35 gopalv Exp $ */ ++ if(!(my_copy_zend_op(dst->opcodes+i, src->opcodes+i, ctxt TSRMLS_CC))) { ++ return NULL; ++ } + -+#ifndef APC_COMPILE_H -+#define APC_COMPILE_H ++#ifdef ZEND_ENGINE_2_4 ++ if (zo->op1_type == IS_CONST) { ++ dst->opcodes[i].op1.literal = src->opcodes[i].op1.literal - src->literals + dst->literals; ++ } ++ if (zo->op2_type == IS_CONST) { ++ dst->opcodes[i].op2.literal = src->opcodes[i].op2.literal - src->literals + dst->literals; ++ } ++ if (zo->result_type == IS_CONST) { ++ dst->opcodes[i].result.literal = src->opcodes[i].result.literal - src->literals + dst->literals; ++ } ++#endif + -+/* -+ * This module encapsulates most of the complexity involved in deep-copying -+ * the Zend compiler data structures. The routines are allocator-agnostic, so -+ * the same function can be used for copying to and from shared memory. -+ */ ++ /* This code breaks apc's rule#1 - cache what you compile */ ++ if((APCG(fpstat)==0) && APCG(canonicalize)) { ++ /* not pool allocated, because the pool allocations eat up shm space */ ++ fileinfo = (apc_fileinfo_t*) apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC); ++#ifdef ZEND_ENGINE_2_4 ++ if((zo->opcode == ZEND_INCLUDE_OR_EVAL) && ++ (zo->op1_type == IS_CONST && Z_TYPE_P(zo->op1.zv) == IS_STRING)) { ++ /* constant includes */ ++ if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(zo->op1.zv),Z_STRLEN_P(zo->op1.zv))) { ++ if (apc_search_paths(Z_STRVAL_P(zo->op1.zv), PG(include_path), fileinfo TSRMLS_CC) == 0) { ++#else ++ if((zo->opcode == ZEND_INCLUDE_OR_EVAL) && ++ (zo->op1.op_type == IS_CONST && zo->op1.u.constant.type == IS_STRING)) { ++ /* constant includes */ ++ if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(&zo->op1.u.constant),Z_STRLEN_P(&zo->op1.u.constant))) { ++ if (apc_search_paths(Z_STRVAL_P(&zo->op1.u.constant), PG(include_path), fileinfo TSRMLS_CC) == 0) { ++#endif ++ if((fullpath = realpath(fileinfo->fullpath, canon_path))) { ++ /* everything has to go through a realpath() */ ++ zend_op *dzo = &(dst->opcodes[i]); ++#ifdef ZEND_ENGINE_2_4 ++ dzo->op1.literal = (zend_literal*) apc_pool_alloc(pool, sizeof(zend_literal)); ++ Z_STRLEN_P(dzo->op1.zv) = strlen(fullpath); ++ Z_STRVAL_P(dzo->op1.zv) = apc_pstrdup(fullpath, pool TSRMLS_CC); ++ Z_TYPE_P(dzo->op1.zv) = IS_STRING; ++ Z_SET_REFCOUNT_P(dzo->op1.zv, 2); ++ Z_SET_ISREF_P(dzo->op1.zv); ++ dzo->op1.literal->hash_value = zend_hash_func(Z_STRVAL_P(dzo->op1.zv), Z_STRLEN_P(dzo->op1.zv)+1); ++#else ++ dzo->op1.u.constant.value.str.len = strlen(fullpath); ++ dzo->op1.u.constant.value.str.val = apc_pstrdup(fullpath, pool TSRMLS_CC); ++#endif ++ } ++ } ++ } ++ } ++ apc_php_free(fileinfo TSRMLS_CC); ++ } ++ } + -+#include "apc.h" -+#include "apc_php.h" ++ if(flags == NULL || flags->has_jumps) { ++ apc_fixup_op_array_jumps(dst,src); ++ } + -+/* {{{ struct definition: apc_function_t */ -+typedef struct apc_function_t apc_function_t; -+struct apc_function_t { -+ char* name; /* the function name */ -+ int name_len; /* length of name */ -+ zend_function* function; /* the zend function data structure */ -+}; -+/* }}} */ ++ /* copy the break-continue array */ ++ if (src->brk_cont_array) { ++ CHECK(dst->brk_cont_array = apc_pmemcpy(src->brk_cont_array, ++ sizeof(src->brk_cont_array[0]) * src->last_brk_cont, ++ pool TSRMLS_CC)); ++ } + -+/* {{{ struct definition: apc_class_t */ -+typedef struct apc_class_t apc_class_t; -+struct apc_class_t { -+ char* name; /* the class name */ -+ int name_len; /* length of name */ -+ int is_derived; /* true if this is a derived class */ -+ char* parent_name; /* the parent class name */ -+ zend_class_entry* class_entry; /* the zend class data structure */ -+}; -+/* }}} */ ++ /* copy the table of static variables */ ++ if (src->static_variables) { ++ CHECK(dst->static_variables = my_copy_static_variables(src, ctxt TSRMLS_CC)); ++ } + -+/* {{{ struct definition: apc_opflags_t */ -+typedef struct apc_opflags_t apc_opflags_t; -+struct apc_opflags_t { -+ unsigned int has_jumps : 1; /* has jump offsets */ -+ unsigned int deep_copy : 1; /* needs deep copy */ ++ if (src->try_catch_array) { ++ CHECK(dst->try_catch_array = apc_pmemcpy(src->try_catch_array, ++ sizeof(src->try_catch_array[0]) * src->last_try_catch, ++ pool TSRMLS_CC)); ++ } + -+ /* autoglobal bits */ -+ unsigned int _POST : 1; -+ unsigned int _GET : 1; -+ unsigned int _COOKIE : 1; -+ unsigned int _SERVER : 1; -+ unsigned int _ENV : 1; -+ unsigned int _FILES : 1; -+ unsigned int _REQUEST : 1; -+ unsigned int unknown_global : 1; -+}; -+/* }}} */ ++#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */ ++ if (src->vars) { ++ CHECK(dst->vars = apc_pmemcpy(src->vars, ++ sizeof(src->vars[0]) * src->last_var, ++ pool TSRMLS_CC)); + -+/* -+ * These are the top-level copy functions. -+ */ ++ for(i = 0; i < src->last_var; i++) dst->vars[i].name = NULL; + -+extern zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC); -+extern zend_class_entry* apc_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate); -+extern apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC); -+extern apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC); -+extern zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate); ++ for(i = 0; i < src->last_var; i++) { ++ CHECK(dst->vars[i].name = apc_string_pmemcpy(src->vars[i].name, ++ src->vars[i].name_len + 1, ++ pool TSRMLS_CC)); ++ } ++ } ++#endif + -+/* -+ * Deallocation functions corresponding to the copy functions above. -+ */ ++ if (src->doc_comment) { ++ CHECK(dst->doc_comment ++ = apc_pmemcpy(src->doc_comment, (src->doc_comment_len + 1), pool TSRMLS_CC)); ++ } + -+extern void apc_free_op_array(zend_op_array* src, apc_free_t deallocate); -+extern void apc_free_functions(apc_function_t* src, apc_free_t deallocate); -+extern void apc_free_classes(apc_class_t* src, apc_free_t deallocate); -+extern void apc_free_zval(zval* src, apc_free_t deallocate); ++ return dst; ++} ++/* }}} */ + -+/* -+ * These "copy-for-execution" functions must be called after retrieving an -+ * object from the shared cache. They do the minimal amount of work necessary -+ * to allow multiple processes to concurrently execute the same VM data -+ * structures. -+ */ + -+extern zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC); -+extern zend_function* apc_copy_function_for_execution(zend_function* src); -+extern zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived); ++/* {{{ apc_copy_new_functions */ ++apc_function_t* apc_copy_new_functions(int old_count, apc_context_t* ctxt TSRMLS_DC) ++{ ++ apc_function_t* array; ++ int new_count; /* number of new functions in table */ ++ int i; ++ apc_pool* pool = ctxt->pool; + -+/* -+ * The "free-after-execution" function performs a cursory clean up of the class data -+ * This is required to minimize memory leak warnings and to ensure correct destructor -+ * ordering of some variables. -+ */ -+extern void apc_free_class_entry_after_execution(zend_class_entry* src); ++ new_count = zend_hash_num_elements(CG(function_table)) - old_count; ++ assert(new_count >= 0); + -+/* -+ * Optimization callback definition and registration function. -+ */ -+typedef zend_op_array* (*apc_optimize_function_t) (zend_op_array* TSRMLS_DC); -+extern apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC); ++ CHECK(array = ++ (apc_function_t*) ++ apc_pool_alloc(pool, (sizeof(apc_function_t) * (new_count + 1)))); + -+#endif ++ if (new_count == 0) { ++ array[0].function = NULL; ++ return array; ++ } + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_debug.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_debug.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,57 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | Arun C. Murthy | -+ | Gopal Vijayaraghavan | -+ +----------------------------------------------------------------------+ ++ /* Skip the first `old_count` functions in the table */ ++ zend_hash_internal_pointer_reset(CG(function_table)); ++ for (i = 0; i < old_count; i++) { ++ zend_hash_move_forward(CG(function_table)); ++ } + -+ 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. ++ /* Add the next `new_count` functions to our array */ ++ for (i = 0; i < new_count; i++) { ++ char* key; ++ uint key_size; ++ zend_function* fun; + -+ All other licensing and usage conditions are those of the PHP Group. -+*/ -+ -+/* $Id: apc_debug.c,v 3.6 2006/12/07 23:51:28 gopalv Exp $ */ -+#include "apc.h" -+#include -+#include "zend_compile.h" -+ -+#ifdef __DEBUG_APC__ ++ zend_hash_get_current_key_ex(CG(function_table), ++ &key, ++ &key_size, ++ NULL, ++ 0, ++ NULL); + -+#include ++ zend_hash_get_current_data(CG(function_table), (void**) &fun); + -+/* keep track of vld_dump_oparray() signature */ -+typedef void (*vld_dump_f) (zend_op_array * TSRMLS_DC); ++ CHECK(array[i].name = apc_pmemcpy(key, (int) key_size, pool TSRMLS_CC)); ++ array[i].name_len = (int) key_size-1; ++ CHECK(array[i].function = my_copy_function(NULL, fun, ctxt TSRMLS_CC)); ++ zend_hash_move_forward(CG(function_table)); ++ } + -+#endif ++ array[i].function = NULL; ++ return array; ++} ++/* }}} */ + -+void dump(zend_op_array *op_array TSRMLS_DC) ++/* {{{ apc_copy_new_classes */ ++apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_context_t *ctxt TSRMLS_DC) +{ -+#ifdef __DEBUG_APC__ -+ vld_dump_f dump_op_array = dlsym(NULL, "vld_dump_oparray"); ++ apc_class_t* array; ++ int new_count; /* number of new classes in table */ ++ int i; ++ apc_pool* pool = ctxt->pool; + -+ if(dump_op_array) -+ { -+ dump_op_array(op_array TSRMLS_CC); -+ } -+ else -+ { -+ apc_wprint("vld is not installed or something even worse."); -+ } -+#endif -+} -Index: php-5.2.3/ext/apc/apc_debug.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_debug.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1 @@ -+void dump(zend_op_array * TSRMLS_DC); -Index: php-5.2.3/ext/apc/apc.dsp -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc.dsp 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,207 @@ -+# Microsoft Developer Studio Project File - Name="apc" - Package Owner=<4> -+# Microsoft Developer Studio Generated Build File, Format Version 6.00 -+# ** DO NOT EDIT ** -+ -+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -+ -+CFG=apc - Win32 Debug_TS -+!MESSAGE This is not a valid makefile. To build this project using NMAKE, -+!MESSAGE use the Export Makefile command and run -+!MESSAGE -+!MESSAGE NMAKE /f "apc.mak". -+!MESSAGE -+!MESSAGE You can specify a configuration when running NMAKE -+!MESSAGE by defining the macro CFG on the command line. For example: -+!MESSAGE -+!MESSAGE NMAKE /f "apc.mak" CFG="apc - Win32 Debug_TS" -+!MESSAGE -+!MESSAGE Possible choices for configuration are: -+!MESSAGE -+!MESSAGE "apc - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") -+!MESSAGE "apc - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") -+!MESSAGE -+ -+# Begin Project -+# PROP AllowPerConfigDependencies 0 -+# PROP Scc_ProjName "" -+# PROP Scc_LocalPath "" -+CPP=cl.exe -+MTL=midl.exe -+RSC=rc.exe -+ -+!IF "$(CFG)" == "apc - Win32 Debug_TS" -+ -+# PROP BASE Use_MFC 0 -+# PROP BASE Use_Debug_Libraries 1 -+# PROP BASE Output_Dir "Debug_TS" -+# PROP BASE Intermediate_Dir "Debug_TS" -+# PROP BASE Target_Dir "" -+# PROP Use_MFC 0 -+# PROP Use_Debug_Libraries 1 -+# PROP Output_Dir "Debug_TS" -+# PROP Intermediate_Dir "Debug_TS" -+# PROP Ignore_Export_Lib 0 -+# PROP Target_Dir "" -+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /GZ /c -+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\php4" /I "..\..\..\php4\main" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\win32" /I "..\..\..\php4\regex" /D "TSRM_LOCKS" /D HAVE_APC=1 /D "COMPILE_DL_APC" /D ZEND_DEBUG=1 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /GZ /c -+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -+# ADD BASE RSC /l 0x409 /d "_DEBUG" -+# ADD RSC /l 0x409 /d "_DEBUG" -+BSC32=bscmake.exe -+# ADD BASE BSC32 /nologo -+# ADD BSC32 /nologo -+LINK32=link.exe -+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -+# ADD LINK32 php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug_TS/php_apc.dll" /pdbtype:sept /libpath:"..\..\..\php4\Debug_TS" -+ -+!ELSEIF "$(CFG)" == "apc - Win32 Release_TS" -+ -+# PROP BASE Use_MFC 0 -+# PROP BASE Use_Debug_Libraries 0 -+# PROP BASE Output_Dir "Release_TS" -+# PROP BASE Intermediate_Dir "Release_TS" -+# PROP BASE Target_Dir "" -+# PROP Use_MFC 0 -+# PROP Use_Debug_Libraries 0 -+# PROP Output_Dir "Release_TS" -+# PROP Intermediate_Dir "Release_TS" -+# PROP Ignore_Export_Lib 0 -+# PROP Target_Dir "" -+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /c -+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\php4" /I "..\..\..\php4\main" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\win32" /I "..\..\..\php4\regex" /D "TSRM_LOCKS" /D HAVE_APC=1 /D "COMPILE_DL_APC" /D ZEND_DEBUG=0 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /c -+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -+# ADD BASE RSC /l 0x409 /d "NDEBUG" -+# ADD RSC /l 0x409 /d "NDEBUG" -+BSC32=bscmake.exe -+# ADD BASE BSC32 /nologo -+# ADD BSC32 /nologo -+LINK32=link.exe -+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -+# ADD LINK32 php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../Release_TS/php_apc.dll" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\php4\Release_TS_Inline" -+ -+!ENDIF -+ -+# Begin Target -+ -+# Name "apc - Win32 Debug_TS" -+# Name "apc - Win32 Release_TS" -+# Begin Group "Source Files" -+ -+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -+# Begin Source File -+ -+SOURCE=.\apc.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_cache.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_compile.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_debug.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_fcntl_win32.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_main.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_rfc1867.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_shm.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_sma.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_stack.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_zend.c -+# End Source File -+# Begin Source File -+ -+SOURCE=.\php_apc.c -+# End Source File -+# End Group -+# Begin Group "Header Files" -+ -+# PROP Default_Filter "h;hpp;hxx;hm;inl" -+# Begin Source File -+ -+SOURCE=.\apc.h -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_cache.h -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_compile.h -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_debug.h -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_fcntl.h -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_globals.h -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_lock.h -+# End Source File -+# Begin Source File -+ -+SOURCE=.\apc_main.h -+# End Source File -+# Begin Source File ++ new_count = zend_hash_num_elements(CG(class_table)) - old_count; ++ assert(new_count >= 0); + -+SOURCE=.\apc_php.h -+# End Source File -+# Begin Source File ++ CHECK(array = ++ (apc_class_t*) ++ apc_pool_alloc(pool, (sizeof(apc_class_t) * (new_count + 1)))); + -+SOURCE=.\apc_shm.h -+# End Source File -+# Begin Source File ++ if (new_count == 0) { ++ array[0].class_entry = NULL; ++ return array; ++ } + -+SOURCE=.\apc_sma.h -+# End Source File -+# Begin Source File ++ /* Skip the first `old_count` classes in the table */ ++ zend_hash_internal_pointer_reset(CG(class_table)); ++ for (i = 0; i < old_count; i++) { ++ zend_hash_move_forward(CG(class_table)); ++ } + -+SOURCE=.\apc_stack.h -+# End Source File -+# Begin Source File ++ /* Add the next `new_count` classes to our array */ ++ for (i = 0; i < new_count; i++) { ++ char* key; ++ uint key_size; ++ zend_class_entry* elem = NULL; + -+SOURCE=.\apc_zend.h -+# End Source File -+# Begin Source File ++ array[i].class_entry = NULL; + -+SOURCE=.\php_apc.h -+# End Source File -+# End Group -+# Begin Group "Resource Files" -+ -+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -+# End Group -+# End Target -+# End Project -Index: php-5.2.3/ext/apc/apc_fcntl.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_fcntl.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,118 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: George Schlossnagle | -+ | Rasmus Lerdorf | -+ +----------------------------------------------------------------------+ ++ zend_hash_get_current_key_ex(CG(class_table), ++ &key, ++ &key_size, ++ NULL, ++ 0, ++ NULL); + -+ 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. ++ zend_hash_get_current_data(CG(class_table), (void**) &elem); + -+ All other licensing and usage conditions are those of the PHP Group. + -+ */ ++ elem = *((zend_class_entry**)elem); + -+/* $Id: apc_fcntl.c,v 3.25 2006/06/19 02:52:49 rasmus Exp $ */ ++ CHECK(array[i].name = apc_pmemcpy(key, (int) key_size, pool TSRMLS_CC)); ++ array[i].name_len = (int) key_size-1; ++ CHECK(array[i].class_entry = my_copy_class_entry(NULL, elem, ctxt TSRMLS_CC)); + -+#include "apc_fcntl.h" -+#include "apc.h" -+#include -+#include ++ /* ++ * If the class has a pointer to its parent class, save the parent ++ * name so that we can enable compile-time inheritance when we reload ++ * the child class; otherwise, set the parent name to null and scan ++ * the op_array to determine if this class inherits from some base ++ * class at execution-time. ++ */ + -+int apc_fcntl_create(const char* pathname) -+{ -+ int fd; -+ if(pathname == NULL) { -+ char lock_path[] = "/tmp/.apc.XXXXXX"; -+ mktemp(lock_path); -+ fd = open(lock_path, O_RDWR|O_CREAT, 0666); -+ if(fd > 0 ) { -+ unlink(lock_path); -+ return fd; -+ } else { -+ apc_eprint("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", lock_path); -+ return -1; ++ if (elem->parent) { ++ CHECK(array[i].parent_name = apc_pstrdup(elem->parent->name, pool TSRMLS_CC)); ++ } ++ else { ++ array[i].parent_name = NULL; + } -+ } -+ fd = open(pathname, O_RDWR|O_CREAT, 0666); -+ if(fd > 0 ) { -+ unlink(pathname); -+ return fd; -+ } -+ apc_eprint("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname); -+ return -1; -+} -+ -+void apc_fcntl_destroy(int fd) -+{ -+ close(fd); -+} -+ -+static int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len) -+{ -+ int ret; -+ struct flock lock; -+ -+ lock.l_type = type; -+ lock.l_start = offset; -+ lock.l_whence = whence; -+ lock.l_len = len; -+ lock.l_pid = 0; -+ -+ do { ret = fcntl(fd, cmd, &lock) ; } -+ while(ret < 0 && errno == EINTR); -+ return(ret); -+} + -+void apc_fcntl_lock(int fd) -+{ -+ if(lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) { -+ apc_eprint("apc_fcntl_lock failed:"); ++ zend_hash_move_forward(CG(class_table)); + } -+} + -+void apc_fcntl_rdlock(int fd) -+{ -+ if(lock_reg(fd, F_SETLKW, F_RDLCK, 0, SEEK_SET, 0) < 0) { -+ apc_eprint("apc_fcntl_rdlock failed:"); -+ } ++ array[i].class_entry = NULL; ++ return array; +} ++/* }}} */ + -+zend_bool apc_fcntl_nonblocking_lock(int fd) -+{ -+ if(lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0) { -+ if(errno==EACCES||errno==EAGAIN) return 0; -+ else apc_eprint("apc_fcntl_lock failed:"); -+ } -+ return 1; -+} ++/* Used only by my_prepare_op_array_for_execution */ ++#ifdef ZEND_ENGINE_2_4 ++# define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION() \ ++ /* The fetch is only required if auto_globals_jit=1 */ \ ++ if((zo->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL && \ ++ zo->op1_type == IS_CONST && \ ++ Z_TYPE_P(zo->op1.zv) == IS_STRING && \ ++ Z_STRVAL_P(zo->op1.zv)[0] == '_') { \ ++ (void)zend_is_auto_global(Z_STRVAL_P(zo->op1.zv), \ ++ Z_STRLEN_P(zo->op1.zv) \ ++ TSRMLS_CC); \ ++ } ++#else ++# define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION() \ ++ /* The fetch is only required if auto_globals_jit=1 */ \ ++ if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL && \ ++ zo->op1.op_type == IS_CONST && \ ++ zo->op1.u.constant.type == IS_STRING && \ ++ zo->op1.u.constant.value.str.val[0] == '_') { \ ++ \ ++ znode* varname = &zo->op1; \ ++ (void)zend_is_auto_global(varname->u.constant.value.str.val, \ ++ varname->u.constant.value.str.len \ ++ TSRMLS_CC); \ ++ } ++#endif + -+void apc_fcntl_unlock(int fd) ++/* {{{ my_prepare_op_array_for_execution */ ++static int my_prepare_op_array_for_execution(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ if(lock_reg(fd, F_SETLKW, F_UNLCK, 0, SEEK_SET, 0) < 0) { -+ apc_eprint("apc_fcntl_unlock failed:"); -+ } -+} -+ -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_fcntl.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_fcntl.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,50 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt. | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: George Schlossnagle | -+ | Rasmus Lerdorf | -+ +----------------------------------------------------------------------+ ++ /* combine my_fetch_global_vars and my_copy_data_exceptions. ++ * - Pre-fetch superglobals which would've been pre-fetched in parse phase. ++ * - If the opcode stream contain mutable data, ensure a copy. ++ * - Fixup array jumps in the same loop. ++ */ ++ int i=src->last; ++ zend_op *zo; ++ zend_op *dzo; ++ apc_opflags_t * flags = apc_reserved_offset != -1 ? ++ (apc_opflags_t*) & (src->reserved[apc_reserved_offset]) : NULL; ++ int needcopy = flags ? flags->deep_copy : 1; ++ /* auto_globals_jit was not in php4 */ ++ int do_prepare_fetch_global = PG(auto_globals_jit) && (flags == NULL || flags->unknown_global); + -+ 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. ++#define FETCH_AUTOGLOBAL(member) do { \ ++ if(flags && flags->member == 1) { \ ++ zend_is_auto_global(#member,\ ++ (sizeof(#member) - 1)\ ++ TSRMLS_CC);\ ++ } \ ++} while(0); + -+ All other licensing and usage conditions are those of the PHP Group. ++ FETCH_AUTOGLOBAL(_GET); ++ FETCH_AUTOGLOBAL(_POST); ++ FETCH_AUTOGLOBAL(_COOKIE); ++ FETCH_AUTOGLOBAL(_SERVER); ++ FETCH_AUTOGLOBAL(_ENV); ++ FETCH_AUTOGLOBAL(_FILES); ++ FETCH_AUTOGLOBAL(_REQUEST); ++ FETCH_AUTOGLOBAL(_SESSION); ++#ifdef ZEND_ENGINE_2_4 ++ FETCH_AUTOGLOBAL(GLOBALS); ++#endif + -+ */ ++ if(needcopy) { + -+/* $Id: apc_fcntl.h,v 3.14 2006/05/31 22:24:48 rasmus Exp $ */ ++#ifdef ZEND_ENGINE_2_4 ++ if (src->literals) { ++ zend_literal *p, *q, *end; ++ ++ q = src->literals; ++ p = dst->literals = (zend_literal*) apc_xmemcpy(src->literals, ++ sizeof(zend_literal) * src->last_literal, ++ apc_php_malloc TSRMLS_CC); ++ end = p + src->last_literal; ++ while (p < end) { ++ if (Z_TYPE(q->constant) == IS_CONSTANT_ARRAY) { ++ my_copy_zval(&p->constant, &q->constant, ctxt TSRMLS_CC); ++ } ++ p++; ++ q++; ++ } ++ } ++#endif + -+#ifndef APC_FCNTL_H -+#define APC_FCNTL_H ++ dst->opcodes = (zend_op*) apc_xmemcpy(src->opcodes, ++ sizeof(zend_op) * src->last, ++ apc_php_malloc TSRMLS_CC); ++ zo = src->opcodes; ++ dzo = dst->opcodes; ++ while(i > 0) { + ++#ifdef ZEND_ENGINE_2_4 ++ if(zo->op1_type == IS_CONST) { ++ dzo->op1.literal = zo->op1.literal - src->literals + dst->literals; ++ } ++ if(zo->op2_type == IS_CONST) { ++ dzo->op2.literal = zo->op2.literal - src->literals + dst->literals; ++ } ++ if(zo->result_type == IS_CONST) { ++ dzo->result.literal = zo->result.literal - src->literals + dst->literals; ++ } ++#else ++ if( ((zo->op1.op_type == IS_CONST && ++ zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) || ++ ((zo->op2.op_type == IS_CONST && ++ zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) { + -+extern int apc_fcntl_create(const char* pathname); -+extern void apc_fcntl_destroy(int fd); -+extern void apc_fcntl_lock(int fd); -+extern void apc_fcntl_rdlock(int fd); -+extern void apc_fcntl_unlock(int fd); -+extern unsigned char apc_fcntl_nonblocking_lock(int fd); ++ if(!(my_copy_zend_op(dzo, zo, ctxt TSRMLS_CC))) { ++ assert(0); /* emalloc failed or a bad constant array */ ++ } ++ } +#endif + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_fcntl_win32.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_fcntl_win32.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,117 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: George Schlossnagle | -+ | Edin Kadribasic | -+ +----------------------------------------------------------------------+ -+ -+ 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. -+ -+ */ ++ switch(zo->opcode) { ++#ifdef ZEND_ENGINE_2_3 ++ case ZEND_GOTO: ++#endif ++ case ZEND_JMP: ++#ifdef ZEND_ENGINE_2_4 ++ dzo->op1.jmp_addr = dst->opcodes + ++ (zo->op1.jmp_addr - src->opcodes); ++#else ++ dzo->op1.u.jmp_addr = dst->opcodes + ++ (zo->op1.u.jmp_addr - src->opcodes); ++#endif ++ break; ++ case ZEND_JMPZ: ++ case ZEND_JMPNZ: ++ case ZEND_JMPZ_EX: ++ case ZEND_JMPNZ_EX: ++#ifdef ZEND_ENGINE_2_3 ++ case ZEND_JMP_SET: ++#endif ++#ifdef ZEND_ENGINE_2_4 ++ case ZEND_JMP_SET_VAR: ++#endif ++#ifdef ZEND_ENGINE_2_4 ++ dzo->op2.jmp_addr = dst->opcodes + ++ (zo->op2.jmp_addr - src->opcodes); ++#else ++ dzo->op2.u.jmp_addr = dst->opcodes + ++ (zo->op2.u.jmp_addr - src->opcodes); ++#endif ++ break; ++ case ZEND_FETCH_R: ++ case ZEND_FETCH_W: ++ case ZEND_FETCH_IS: ++ case ZEND_FETCH_FUNC_ARG: ++ if(do_prepare_fetch_global) ++ { ++ APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION(); ++ } ++ break; ++ default: ++ break; ++ } ++ i--; ++ zo++; ++ dzo++; ++ } ++ } else { /* !needcopy */ ++ /* The fetch is only required if auto_globals_jit=1 */ ++ if(do_prepare_fetch_global) ++ { ++ zo = src->opcodes; ++ while(i > 0) { + -+/* $Id: apc_fcntl_win32.c,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */ ++ if(zo->opcode == ZEND_FETCH_R || ++ zo->opcode == ZEND_FETCH_W || ++ zo->opcode == ZEND_FETCH_IS || ++ zo->opcode == ZEND_FETCH_FUNC_ARG ++ ) { ++ APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION(); ++ } + -+#include "apc_fcntl.h" -+#include "apc.h" -+#include -+#include -+#include -+#include -+#include -+#include ++ i--; ++ zo++; ++ } ++ } ++ } ++ return 1; ++} ++/* }}} */ + -+int apc_fcntl_create(const char* pathname) ++/* {{{ apc_copy_op_array_for_execution */ ++zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ char *lock_file = emalloc(MAXPATHLEN); -+ HANDLE fd; -+ DWORD tmplen; -+ static int i=0; -+ -+ tmplen = GetTempPath(MAXPATHLEN, lock_file); -+ if (!tmplen) { -+ efree(lock_file); -+ return -1; -+ } ++ if(dst == NULL) { ++ dst = (zend_op_array*) emalloc(sizeof(src[0])); ++ } ++ memcpy(dst, src, sizeof(src[0])); ++ dst->static_variables = my_copy_static_variables(src, ctxt TSRMLS_CC); + -+ snprintf(lock_file + tmplen, MAXPATHLEN - tmplen - 1, "apc.lock.%d", i++); -+ -+ fd = CreateFile(lock_file, -+ GENERIC_READ | GENERIC_WRITE, -+ FILE_SHARE_READ | FILE_SHARE_WRITE, -+ NULL, -+ OPEN_ALWAYS, -+ FILE_ATTRIBUTE_NORMAL, -+ NULL); -+ ++ /* memory leak */ ++ dst->refcount = apc_pmemcpy(src->refcount, ++ sizeof(src->refcount[0]), ++ ctxt->pool TSRMLS_CC); + -+ if (fd == INVALID_HANDLE_VALUE) { -+ apc_eprint("apc_fcntl_create: could not open %s", lock_file); -+ efree(lock_file); -+ return -1; -+ } -+ -+ efree(lock_file); -+ return (int)fd; -+} ++ my_prepare_op_array_for_execution(dst,src, ctxt TSRMLS_CC); + -+void apc_fcntl_destroy(int fd) -+{ -+ CloseHandle((HANDLE)fd); ++ return dst; +} ++/* }}} */ + -+void apc_fcntl_lock(int fd) ++/* {{{ apc_copy_function_for_execution */ ++zend_function* apc_copy_function_for_execution(zend_function* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ OVERLAPPED offset = {0, 0, 0, 0, NULL}; -+ -+ if (!LockFileEx((HANDLE)fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &offset)) { -+ apc_eprint("apc_fcntl_lock failed errno:%d", GetLastError()); -+ } ++ zend_function* dst; ++ ++ dst = (zend_function*) emalloc(sizeof(src[0])); ++ memcpy(dst, src, sizeof(src[0])); ++ apc_copy_op_array_for_execution(&(dst->op_array), &(src->op_array), ctxt TSRMLS_CC); ++ return dst; +} ++/* }}} */ + -+void apc_fcntl_rdlock(int fd) ++/* {{{ apc_copy_function_for_execution_ex */ ++zend_function* apc_copy_function_for_execution_ex(void *dummy, zend_function* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ OVERLAPPED offset = {0, 0, 0, 0, NULL}; -+ -+ if (!LockFileEx((HANDLE)fd, 0, 0, 1, 0, &offset)) { -+ apc_eprint("apc_fcntl_rdlock failed errno:%d", GetLastError()); -+ } ++ if(src->type==ZEND_INTERNAL_FUNCTION || src->type==ZEND_OVERLOADED_FUNCTION) return src; ++ return apc_copy_function_for_execution(src, ctxt TSRMLS_CC); +} ++/* }}} */ + -+void apc_fcntl_unlock(int fd) ++/* {{{ apc_copy_class_entry_for_execution */ ++zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, apc_context_t* ctxt TSRMLS_DC) +{ -+ OVERLAPPED offset = {0, 0, 0, 0, NULL}; ++#ifdef ZEND_ENGINE_2_4 ++ int i; ++#endif ++ zend_class_entry* dst = (zend_class_entry*) apc_pool_alloc(ctxt->pool, sizeof(src[0])); ++ memcpy(dst, src, sizeof(src[0])); + -+ if (!UnlockFileEx((HANDLE)fd, 0, 1, 0, &offset)) { -+ DWORD error_code = GetLastError(); -+ /* Ignore already unlocked error */ -+ if (error_code != ERROR_NOT_LOCKED) { -+ apc_eprint("apc_fcntl_unlock failed errno:%d", error_code); -+ } -+ } -+} ++ if(src->num_interfaces) ++ { ++ /* These are slots to be populated later by ADD_INTERFACE insns */ ++ dst->interfaces = apc_php_malloc( ++ (sizeof(zend_class_entry*) * src->num_interfaces) TSRMLS_CC); ++ memset(dst->interfaces, 0, ++ sizeof(zend_class_entry*) * src->num_interfaces); ++ } ++ else ++ { ++ /* assert(dst->interfaces == NULL); */ ++ } + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_futex.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_futex.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,116 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Brian Shire | -+ +----------------------------------------------------------------------+ ++ /* Deep-copy the class properties, because they will be modified */ + -+ */ ++#ifdef ZEND_ENGINE_2_4 ++ dst->name = apc_string_pmemcpy((char*)src->name, src->name_length+1, ctxt->pool TSRMLS_CC); ++ dst->default_properties_count = src->default_properties_count; ++ if (src->default_properties_count) { ++ dst->default_properties_table = (zval**) apc_php_malloc((sizeof(zval*) * src->default_properties_count) TSRMLS_CC); ++ for (i = 0; i < src->default_properties_count; i++) { ++ if (src->default_properties_table[i]) { ++ my_copy_zval_ptr(&dst->default_properties_table[i], (const zval**)&src->default_properties_table[i], ctxt TSRMLS_CC); ++ } else { ++ dst->default_properties_table[i] = NULL; ++ } ++ } ++ } else { ++ dst->default_properties_table = NULL; ++ } ++#else ++ my_copy_hashtable(&dst->default_properties, ++ &src->default_properties, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt); ++#endif + -+/* $Id: apc_futex.c,v 3.2 2006/10/12 08:23:16 shire Exp $ */ -+ -+/*************************************************************************** -+* Futex (Fast Userspace Mutex) support for APC -+* -+* Futex support provides user space locking with system calls only -+* for the contended cases. Some required reading for this functionality is: -+* -+* 'Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux' -+* by Hubertus Franke, Rusty Russell, and Matthew Kirkwood -+* http://www.realitydiluted.com/nptl-uclibc/docs/futex.pdf -+* -+* 'Futexes are Tricky' by Ulrich Drepper -+* http://people.redhat.com/drepper/futex.pdf -+* -+* -+* This implementation is optimized and designed for the i386 and x86_64 -+* architectures. Other architectures may require additional design -+* to efficiently and safely implement this functionality. -+* -+* Lock values are: -+* 0 = Unlocked -+* 1 = Locked without any waiting processes -+* 2 = Locked with an unknown number of waiting processes -+* -+***************************************************************************/ ++ /* For derived classes, we must also copy the function hashtable (although ++ * we can merely bitwise copy the functions it contains) */ + -+#include "apc.h" -+#include "apc_futex.h" ++ my_copy_hashtable(&dst->function_table, ++ &src->function_table, ++ (ht_copy_fun_t) apc_copy_function_for_execution_ex, ++ 0, ++ ctxt); + -+#ifdef APC_FUTEX_LOCKS ++ my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function_for_execution, src, dst); + ++ /* zend_do_inheritance merges properties_info. ++ * Need only shallow copying as it doesn't hold the pointers. ++ */ ++ my_copy_hashtable(&dst->properties_info, ++ &src->properties_info, ++ (ht_copy_fun_t) my_copy_property_info_for_execution, ++ 0, ++ ctxt); + -+inline int apc_futex_create() -+{ -+ return 0; -+} ++#ifdef ZEND_ENGINE_2_2 ++ /* php5.2 introduced a scope attribute for property info */ ++ my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst); ++#endif + -+inline void apc_futex_destroy(volatile int* lock) -+{ -+ return; -+} ++ /* if inheritance results in a hash_del, it might result in ++ * a pefree() of the pointers here. Deep copying required. ++ */ + -+void apc_futex_lock(volatile int* lock) -+{ -+ int c; -+ -+ /* Attempt to obtain a lock if not currently locked. If the previous -+ * value was not 0 then we did not obtain the lock, and must wait. -+ * If the previous value was 1 (has no waiting processes) then we -+ * set the lock to 2 before blocking on the futex wait operation. -+ * This implementation suffers from the possible difficulty of -+ * efficently implementing the atomic xchg operation on some -+ * architectures, and could also cause unecessary wake operations by -+ * setting the lock to 2 when there are no additional waiters. -+ */ -+ if((c = apc_cmpxchg(lock, 0, 1)) != 0) { -+ if(c != 2) { -+ c = apc_xchg(lock, 2); -+ } -+ while(c != 0) { -+ apc_futex_wait(lock, 2); -+ c = apc_xchg(lock, 2); ++ my_copy_hashtable(&dst->constants_table, ++ &src->constants_table, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt); ++ ++#ifdef ZEND_ENGINE_2_4 ++ dst->default_static_members_count = src->default_static_members_count; ++ if (src->default_static_members_count) { ++ dst->default_static_members_table = (zval**) apc_php_malloc((sizeof(zval*) * src->default_static_members_count) TSRMLS_CC); ++ for (i = 0; i < src->default_static_members_count; i++) { ++ if (src->default_static_members_table[i]) { ++ my_copy_zval_ptr(&dst->default_static_members_table[i], (const zval**)&src->default_static_members_table[i], ctxt TSRMLS_CC); ++ } else { ++ dst->default_static_members_table[i] = NULL; ++ } + } ++ } else { ++ dst->default_static_members_table = NULL; + } -+ -+} ++ dst->static_members_table = dst->default_static_members_table; ++#else ++ my_copy_hashtable(&dst->default_static_members, ++ &src->default_static_members, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt); + -+/* non-blocking lock returns 1 when the lock has been obtained, 0 if it would block */ -+inline zend_bool apc_futex_nonblocking_lock(volatile int* lock) -+{ -+ return apc_cmpxchg(lock, 0, 1) == 0; -+} ++ if(src->static_members != &(src->default_static_members)) ++ { ++ dst->static_members = my_copy_hashtable(NULL, ++ src->static_members, ++ (ht_copy_fun_t) my_copy_zval_ptr, ++ 1, ++ ctxt); ++ } ++ else ++ { ++ dst->static_members = &(dst->default_static_members); ++ } ++#endif + ++ return dst; ++} ++/* }}} */ + -+inline void apc_futex_unlock(volatile int* lock) ++/* {{{ apc_free_class_entry_after_execution */ ++void apc_free_class_entry_after_execution(zend_class_entry* src TSRMLS_DC) +{ -+ /* set the lock to 0, if it's previous values was not 1 (no waiters) -+ * then perform a wake operation on one process letting it know the lock -+ * is available. This is an optimization to save wake calls if there -+ * are no waiting processes for the lock -+ */ -+ if(apc_xchg(lock,0) != 1) { -+ apc_futex_wake(lock, 1); ++ if(src->num_interfaces > 0 && src->interfaces) { ++ apc_php_free(src->interfaces TSRMLS_CC); ++ src->interfaces = NULL; ++ src->num_interfaces = 0; ++ } ++ /* my_destroy_hashtable() does not play nice with refcounts */ ++ ++#ifdef ZEND_ENGINE_2_4 ++ if (src->default_static_members_table) { ++ int i; ++ ++ for (i = 0; i < src->default_static_members_count; i++) { ++ zval_ptr_dtor(&src->default_static_members_table[i]); ++ } ++ efree(src->default_static_members_table); ++ src->default_static_members_table = NULL; ++ } ++ src->static_members_table = NULL; ++ if (src->default_properties_table) { ++ int i; ++ ++ for (i = 0; i < src->default_properties_count; i++) { ++ if (src->default_properties_table[i]) { ++ zval_ptr_dtor(&src->default_properties_table[i]); ++ } ++ } ++ efree(src->default_properties_table); ++ src->default_properties_table = NULL; ++ } ++#else ++ zend_hash_clean(&src->default_static_members); ++ if(src->static_members != &(src->default_static_members)) ++ { ++ zend_hash_destroy(src->static_members); ++ apc_php_free(src->static_members TSRMLS_CC); ++ src->static_members = NULL; ++ } ++ else ++ { ++ src->static_members = NULL; + } -+} + ++ zend_hash_clean(&src->default_properties); +#endif ++ zend_hash_clean(&src->constants_table); + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_futex.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_futex.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,55 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Brian Shire | -+ +----------------------------------------------------------------------+ ++ /* TODO: more cleanup */ ++} ++/* }}} */ + -+ */ ++/* {{{ apc_file_halt_offset */ ++long apc_file_halt_offset(const char *filename TSRMLS_DC) ++{ ++ zend_constant *c; ++ char *name; ++ int len; ++ char haltoff[] = "__COMPILER_HALT_OFFSET__"; ++ long value = -1; + -+/* $Id: apc_futex.h,v 3.2 2006/10/12 08:23:16 shire Exp $ */ ++ zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, filename, strlen(filename), 0); ++ ++ if (zend_hash_find(EG(zend_constants), name, len+1, (void **) &c) == SUCCESS) { ++ value = Z_LVAL(c->value); ++ } ++ ++ pefree(name, 0); + -+#ifndef APC_FUTEX_H -+#define APC_FUTEX_H ++ return value; ++} ++/* }}} */ + -+#include "apc.h" ++/* {{{ apc_do_halt_compiler_register */ ++void apc_do_halt_compiler_register(const char *filename, long halt_offset TSRMLS_DC) ++{ ++ char *name; ++ char haltoff[] = "__COMPILER_HALT_OFFSET__"; ++ int len; ++ ++ if(halt_offset > 0) { ++ ++ zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, ++ filename, strlen(filename), 0); ++ ++ zend_register_long_constant(name, len+1, halt_offset, CONST_CS, 0 TSRMLS_CC); + -+#ifdef APC_FUTEX_LOCKS ++ pefree(name, 0); ++ } ++} ++/* }}} */ + -+#include -+#include -+#include + -+#include "arch/atomic.h" + -+#define sys_futex(futex, op, val, timeout) syscall(SYS_futex, futex, op, val, timeout) -+#define apc_futex_wait(val, oldval) sys_futex((void*)val, FUTEX_WAIT, oldval, NULL) -+#define apc_futex_wake(val, count) sys_futex((void*)val, FUTEX_WAKE, count, NULL) ++/* {{{ my_fixup_function */ ++static void my_fixup_function(Bucket *p, zend_class_entry *src, zend_class_entry *dst) ++{ ++ zend_function* zf = p->pData; ++ ++ #define SET_IF_SAME_NAME(member) \ ++ do { \ ++ if(src->member && !strcmp(zf->common.function_name, src->member->common.function_name)) { \ ++ dst->member = zf; \ ++ } \ ++ } \ ++ while(0) + -+int apc_futex_create(); -+void apc_futex_destroy(volatile int* lock); -+void apc_futex_lock(volatile int* lock); -+void apc_futex_unlock(volatile int* lock); ++ if(zf->common.scope == src) ++ { + -+#endif ++ /* Fixing up the default functions for objects here since ++ * we need to compare with the newly allocated functions ++ * ++ * caveat: a sub-class method can have the same name as the ++ * parent's constructor and create problems. ++ */ + ++ if(zf->common.fn_flags & ZEND_ACC_CTOR) dst->constructor = zf; ++ else if(zf->common.fn_flags & ZEND_ACC_DTOR) dst->destructor = zf; ++ else if(zf->common.fn_flags & ZEND_ACC_CLONE) dst->clone = zf; ++ else ++ { ++ SET_IF_SAME_NAME(__get); ++ SET_IF_SAME_NAME(__set); ++ SET_IF_SAME_NAME(__unset); ++ SET_IF_SAME_NAME(__isset); ++ SET_IF_SAME_NAME(__call); ++#ifdef ZEND_ENGINE_2_2 ++ SET_IF_SAME_NAME(__tostring); ++#endif ++#ifdef ZEND_ENGINE_2_3 ++ SET_IF_SAME_NAME(__callstatic); +#endif ++ } ++ zf->common.scope = dst; ++ } ++ else ++ { ++ /* no other function should reach here */ ++ assert(0); ++ } + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_globals.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_globals.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,110 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt. | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | George Schlossnagle | -+ | Rasmus Lerdorf | -+ | Arun C. Murthy | -+ | Gopal Vijayaraghavan | -+ +----------------------------------------------------------------------+ ++ #undef SET_IF_SAME_NAME ++} ++/* }}} */ + -+ 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. ++#ifdef ZEND_ENGINE_2_2 ++/* {{{ my_fixup_property_info */ ++static void my_fixup_property_info(Bucket *p, zend_class_entry *src, zend_class_entry *dst) ++{ ++ zend_property_info* property_info = (zend_property_info*)p->pData; + -+ All other licensing and usage conditions are those of the PHP Group. ++ if(property_info->ce == src) ++ { ++ property_info->ce = dst; ++ } ++ else ++ { ++ assert(0); /* should never happen */ ++ } ++} ++/* }}} */ ++#endif + -+ */ ++/* {{{ my_fixup_hashtable */ ++static void my_fixup_hashtable(HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst) ++{ ++ Bucket *p; ++ uint i; + -+/* $Id: apc_globals.h,v 3.59 2007/03/21 21:07:28 rasmus Exp $ */ ++ for (i = 0; i < ht->nTableSize; i++) { ++ if(!ht->arBuckets) break; ++ p = ht->arBuckets[i]; ++ while (p != NULL) { ++ fixup(p, src, dst); ++ p = p->pNext; ++ } ++ } ++} ++/* }}} */ + -+#ifndef APC_GLOBALS_H -+#define APC_GLOBALS_H + -+#define APC_VERSION "3.0.14" ++/* {{{ my_check_copy_function */ ++static int my_check_copy_function(Bucket* p, va_list args) ++{ ++ zend_class_entry* src = va_arg(args, zend_class_entry*); ++ zend_function* zf = (zend_function*)p->pData; + -+#include "apc_cache.h" -+#include "apc_stack.h" -+#include "apc_php.h" ++ return (zf->common.scope == src); ++} ++/* }}} */ + -+ZEND_BEGIN_MODULE_GLOBALS(apc) -+ /* configuration parameters */ -+ zend_bool enabled; /* if true, apc is enabled (defaults to true) */ -+ long shm_segments; /* number of shared memory segments to use */ -+ long shm_size; /* size of each shared memory segment (in MB) */ -+ long num_files_hint; /* parameter to apc_cache_create */ -+ long user_entries_hint; -+ long gc_ttl; /* parameter to apc_cache_create */ -+ long ttl; /* parameter to apc_cache_create */ -+ long user_ttl; -+#if APC_MMAP -+ char *mmap_file_mask; /* mktemp-style file-mask to pass to mmap */ -+#endif -+ char** filters; /* array of regex filters that prevent caching */ ++#ifndef ZEND_ENGINE_2_4 ++/* {{{ my_check_copy_default_property */ ++static int my_check_copy_default_property(Bucket* p, va_list args) ++{ ++ zend_class_entry* src = va_arg(args, zend_class_entry*); ++ zend_class_entry* parent = src->parent; ++ zval ** child_prop = (zval**)p->pData; ++ zval ** parent_prop = NULL; + -+ /* module variables */ -+ zend_bool initialized; /* true if module was initialized */ -+ apc_stack_t* cache_stack; /* the stack of cached executable code */ -+ zend_bool cache_by_default; /* true if files should be cached unless filtered out */ -+ /* false if files should only be cached if filtered in */ -+ long slam_defense; /* Probability of a process not caching an uncached file */ -+ size_t* mem_size_ptr; /* size of blocks allocated to file being cached (NULL outside my_compile_file) */ -+ long file_update_protection; /* Age in seconds before a file is eligible to be cached - 0 to disable */ -+ zend_bool enable_cli; /* Flag to override turning APC off for CLI */ -+ long max_file_size; /* Maximum size of file, in bytes that APC will be allowed to cache */ -+ long slam_rand; /* A place to store the slam rand value for the request */ -+ zend_bool fpstat; /* true if fullpath includes should be stat'ed */ -+ zend_bool stat_ctime; /* true if ctime in addition to mtime should be checked */ -+ zend_bool write_lock; /* true for a global write lock */ -+ zend_bool report_autofilter; /* true for auto-filter warnings */ -+ zend_bool include_once; /* Override the ZEND_INCLUDE_OR_EVAL opcode handler to avoid pointless fopen()s [still experimental] */ -+ apc_optimize_function_t apc_optimize_function; /* optimizer function callback */ -+#ifdef MULTIPART_EVENT_FORMDATA -+ zend_bool rfc1867; /* Flag to enable rfc1867 handler */ -+#endif -+ HashTable *copied_zvals; /* my_copy recursion detection list */ -+#ifdef ZEND_ENGINE_2 -+ int reserved_offset; /* offset for apc info in op_array->reserved[] */ -+#endif -+ zend_bool localcache; /* enable local cache */ -+ long localcache_size; /* size of fast cache */ -+ apc_local_cache_t* lcache; /* unlocked local cache */ -+ZEND_END_MODULE_GLOBALS(apc) ++ if (parent && ++ zend_hash_quick_find(&parent->default_properties, p->arKey, ++ p->nKeyLength, p->h, (void **) &parent_prop)==SUCCESS) { + -+/* (the following declaration is defined in php_apc.c) */ -+ZEND_EXTERN_MODULE_GLOBALS(apc) ++ if((parent_prop && child_prop) && (*parent_prop) == (*child_prop)) ++ { ++ return 0; ++ } ++ } + -+#ifdef ZTS -+# define APCG(v) TSRMG(apc_globals_id, zend_apc_globals *, v) -+#else -+# define APCG(v) (apc_globals.v) ++ /* possibly not in the parent */ ++ return 1; ++} ++/* }}} */ +#endif + -+/* True globals */ -+extern apc_cache_t* apc_cache; /* the global compiler cache */ -+extern apc_cache_t* apc_user_cache; /* the global user content cache */ -+extern void* apc_compiled_filters; /* compiled filters */ ++/* {{{ my_check_copy_property_info */ ++static int my_check_copy_property_info(Bucket* p, va_list args) ++{ ++ zend_class_entry* src = va_arg(args, zend_class_entry*); ++ zend_class_entry* parent = src->parent; ++ zend_property_info* child_info = (zend_property_info*)p->pData; ++ zend_property_info* parent_info = NULL; + ++#ifdef ZEND_ENGINE_2_2 ++ /* so much easier */ ++ return (child_info->ce == src); +#endif + -+/* ++ if (parent && ++ zend_hash_quick_find(&parent->properties_info, p->arKey, p->nKeyLength, ++ p->h, (void **) &parent_info)==SUCCESS) { ++ if(parent_info->flags & ZEND_ACC_PRIVATE) ++ { ++ return 1; ++ } ++ if((parent_info->flags & ZEND_ACC_PPP_MASK) != ++ (child_info->flags & ZEND_ACC_PPP_MASK)) ++ { ++ /* TODO: figure out whether ACC_CHANGED is more appropriate ++ * here */ ++ return 1; ++ } ++ return 0; ++ } ++ ++ /* property doesn't exist in parent, copy into cached child */ ++ return 1; ++} ++/* }}} */ ++ ++#ifndef ZEND_ENGINE_2_4 ++/* {{{ my_check_copy_static_member */ ++static int my_check_copy_static_member(Bucket* p, va_list args) ++{ ++ zend_class_entry* src = va_arg(args, zend_class_entry*); ++ HashTable * ht = va_arg(args, HashTable*); ++ zend_class_entry* parent = src->parent; ++ HashTable * parent_ht = NULL; ++ char * member_name; ++ char * class_name = NULL; ++ ++ zend_property_info *parent_info = NULL; ++ zend_property_info *child_info = NULL; ++ zval ** parent_prop = NULL; ++ zval ** child_prop = (zval**)(p->pData); ++ ++ if(!parent) { ++ return 1; ++ } ++ ++ /* these do not need free'ing */ ++#ifdef ZEND_ENGINE_2_2 ++ zend_unmangle_property_name(p->arKey, p->nKeyLength-1, &class_name, &member_name); ++#else ++ zend_unmangle_property_name(p->arKey, &class_name, &member_name); ++#endif ++ ++ /* please refer do_inherit_property_access_check in zend_compile.c ++ * to understand why we lookup in properties_info. ++ */ ++ if((zend_hash_find(&parent->properties_info, member_name, ++ strlen(member_name)+1, (void**)&parent_info) == SUCCESS) ++ && ++ (zend_hash_find(&src->properties_info, member_name, ++ strlen(member_name)+1, (void**)&child_info) == SUCCESS)) ++ { ++ if(ht == &(src->default_static_members)) ++ { ++ parent_ht = &parent->default_static_members; ++ } ++ else ++ { ++ parent_ht = parent->static_members; ++ } ++ ++ if(zend_hash_quick_find(parent_ht, p->arKey, ++ p->nKeyLength, p->h, (void**)&parent_prop) == SUCCESS) ++ { ++ /* they point to the same zval */ ++ if(*parent_prop == *child_prop) ++ { ++ return 0; ++ } ++ } ++ } ++ ++ return 1; ++} ++/* }}} */ ++#endif ++ ++/* {{{ my_check_copy_constant */ ++static int my_check_copy_constant(Bucket* p, va_list args) ++{ ++ zend_class_entry* src = va_arg(args, zend_class_entry*); ++ zend_class_entry* parent = src->parent; ++ zval ** child_const = (zval**)p->pData; ++ zval ** parent_const = NULL; ++ ++ if (parent && ++ zend_hash_quick_find(&parent->constants_table, p->arKey, ++ p->nKeyLength, p->h, (void **) &parent_const)==SUCCESS) { ++ ++ if((parent_const && child_const) && (*parent_const) == (*child_const)) ++ { ++ return 0; ++ } ++ } ++ ++ /* possibly not in the parent */ ++ return 1; ++} ++/* }}} */ ++ ++/* {{{ apc_register_optimizer(apc_optimize_function_t optimizer) ++ * register a optimizer callback function, returns the previous callback ++ */ ++apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC) { ++ apc_optimize_function_t old_optimizer = APCG(apc_optimize_function); ++ APCG(apc_optimize_function) = optimizer; ++ return old_optimizer; ++} ++/* }}} */ ++ ++/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,126 @@ +diff -Naur a/ext/apc/apc_compile.h b/ext/apc/apc_compile.h +--- a/ext/apc/apc_compile.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_compile.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,152 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -5778,8 +5679,6 @@ Index: php-5.2.3/ext/apc/apc.h + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | -+ | George Schlossnagle | -+ | Rasmus Lerdorf | + | Arun C. Murthy | + | Gopal Vijayaraghavan | + +----------------------------------------------------------------------+ @@ -5794,91 +5693,119 @@ Index: php-5.2.3/ext/apc/apc.h + + */ + -+/* $Id: apc.h,v 3.14 2007/03/17 14:01:41 gopalv Exp $ */ ++/* $Id: apc_compile.h 307185 2011-01-06 21:13:11Z gopalv $ */ + -+#ifndef APC_H -+#define APC_H ++#ifndef APC_COMPILE_H ++#define APC_COMPILE_H + +/* -+ * This module defines utilities and helper functions used elsewhere in APC. ++ * This module encapsulates most of the complexity involved in deep-copying ++ * the Zend compiler data structures. The routines are allocator-agnostic, so ++ * the same function can be used for copying to and from shared memory. + */ + -+/* Commonly needed C library headers. */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* UNIX headers (needed for struct stat) */ -+#include -+#include -+#ifndef PHP_WIN32 -+#include -+#endif ++#include "apc.h" ++#include "apc_php.h" ++#include "apc_main.h" ++#include "apc_serializer.h" + -+#ifdef HAVE_CONFIG_H -+#include -+#endif ++/* {{{ struct definition: apc_function_t */ ++typedef struct apc_function_t apc_function_t; ++struct apc_function_t { ++ char* name; /* the function name */ ++ int name_len; /* length of name */ ++ zend_function* function; /* the zend function data structure */ ++}; ++/* }}} */ + -+#include "php.h" ++/* {{{ struct definition: apc_class_t */ ++typedef struct apc_class_t apc_class_t; ++struct apc_class_t { ++ char* name; /* the class name */ ++ int name_len; /* length of name */ ++ char* parent_name; /* the parent class name */ ++ zend_class_entry* class_entry; /* the zend class data structure */ ++}; ++/* }}} */ + -+/* log levels constants (see apc_log) */ -+enum { APC_DBG, APC_NOTICE, APC_WARNING, APC_ERROR }; ++/* {{{ struct definition: apc_opflags_t */ ++typedef struct apc_opflags_t apc_opflags_t; ++struct apc_opflags_t { ++ unsigned int has_jumps : 1; /* has jump offsets */ ++ unsigned int deep_copy : 1; /* needs deep copy */ + -+/* typedefs for extensible memory allocators */ -+typedef void* (*apc_malloc_t)(size_t); -+typedef void (*apc_free_t) (void*); ++ /* autoglobal bits */ ++ unsigned int _POST : 1; ++ unsigned int _GET : 1; ++ unsigned int _COOKIE : 1; ++ unsigned int _SERVER : 1; ++ unsigned int _ENV : 1; ++ unsigned int _FILES : 1; ++ unsigned int _REQUEST : 1; ++ unsigned int _SESSION : 1; ++#ifdef ZEND_ENGINE_2_4 ++ unsigned int GLOBALS : 1; ++#endif ++ unsigned int unknown_global : 1; ++}; ++/* }}} */ + -+/* wrappers for memory allocation routines */ -+extern void* apc_emalloc(size_t n); -+extern void* apc_erealloc(void* p, size_t n); -+extern void apc_efree(void* p); -+extern char* apc_estrdup(const char* s); -+extern void* apc_xstrdup(const char* s, apc_malloc_t f); -+extern void* apc_xmemcpy(const void* p, size_t n, apc_malloc_t f); ++/* ++ * These are the top-level copy functions. ++ */ + -+/* console display functions */ -+extern void apc_log(int level, const char* fmt, ...); -+extern void apc_eprint(const char* fmt, ...); -+extern void apc_wprint(const char* fmt, ...); -+extern void apc_dprint(const char* fmt, ...); -+extern void apc_nprint(const char* fmt, ...); ++extern zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC); ++extern zend_class_entry* apc_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_context_t* ctxt TSRMLS_DC); ++extern apc_function_t* apc_copy_new_functions(int old_count, apc_context_t* ctxt TSRMLS_DC); ++extern apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_context_t* ctxt TSRMLS_DC); ++extern zval* apc_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC); + -+/* string and text manipulation */ -+extern char* apc_append(const char* s, const char* t); -+extern char* apc_substr(const char* s, int start, int length); -+extern char** apc_tokenize(const char* s, char delim); ++#if 0 ++/* ++ * Deallocation functions corresponding to the copy functions above. ++ */ + -+/* filesystem functions */ ++extern void apc_free_op_array(zend_op_array* src, apc_context_t* ctxt); ++extern void apc_free_functions(apc_function_t* src, apc_context_t* ctxt); ++extern void apc_free_classes(apc_class_t* src, apc_context_t* ctxt); ++extern void apc_free_zval(zval* src, apc_context_t* ctxt); ++#endif + -+typedef struct apc_fileinfo_t -+{ -+ char fullpath[MAXPATHLEN+1]; -+ struct stat st_buf; -+} apc_fileinfo_t; ++/* ++ * These "copy-for-execution" functions must be called after retrieving an ++ * object from the shared cache. They do the minimal amount of work necessary ++ * to allow multiple processes to concurrently execute the same VM data ++ * structures. ++ */ + -+#ifndef PHP_WIN32 -+#define apc_stat(f, b) stat(f, b) -+#else -+#define apc_stat(f, b) apc_win32_stat(f, b TSRMLS_CC) -+extern int apc_win32_stat(const char *path, struct stat *buf TSRMLS_DC); -+#endif -+extern int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo); ++extern zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC); ++extern zend_function* apc_copy_function_for_execution(zend_function* src, apc_context_t* ctxt TSRMLS_DC); ++extern zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, apc_context_t* ctxt TSRMLS_DC); + -+/* regular expression wrapper functions */ -+extern void* apc_regex_compile_array(char* patterns[]); -+extern void apc_regex_destroy_array(void* p); -+extern int apc_regex_match_array(void* p, const char* input); ++/* ++ * The "free-after-execution" function performs a cursory clean up of the class data ++ * This is required to minimize memory leak warnings and to ensure correct destructor ++ * ordering of some variables. ++ */ ++extern void apc_free_class_entry_after_execution(zend_class_entry* src TSRMLS_DC); + -+/* apc_crc32: returns the CRC-32 checksum of the first len bytes in buf */ -+extern unsigned int apc_crc32(const char* buf, int len); ++/* ++ * Optimization callback definition and registration function. ++ */ ++typedef zend_op_array* (*apc_optimize_function_t) (zend_op_array* TSRMLS_DC); ++extern apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC); + -+#define APC_NEGATIVE_MATCH 1 -+#define APC_POSITIVE_MATCH 2 ++/* ++ * To handle __COMPILER_HALT_OFFSET__ ++ */ ++long apc_file_halt_offset(const char* filename TSRMLS_DC); ++void apc_do_halt_compiler_register(const char *filename, long halt_offset TSRMLS_DC); + ++/* ++ * apc serialization functions ++ */ ++int APC_SERIALIZER_NAME(php) (APC_SERIALIZER_ARGS); ++int APC_UNSERIALIZER_NAME(php) (APC_UNSERIALIZER_ARGS); +#endif + +/* @@ -5886,19 +5813,18 @@ Index: php-5.2.3/ext/apc/apc.h + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_lock.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_lock.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,105 @@ +diff -Naur a/ext/apc/apc_debug.c b/ext/apc/apc_debug.c +--- a/ext/apc/apc_debug.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_debug.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,70 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -5908,8 +5834,9 @@ Index: php-5.2.3/ext/apc/apc_lock.h + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ -+ | Authors: George Schlossnagle | -+ | Rasmus Lerdorf | ++ | Authors: Daniel Cowgill | ++ | Arun C. Murthy | ++ | Gopal Vijayaraghavan | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 @@ -5919,96 +5846,59 @@ Index: php-5.2.3/ext/apc/apc_lock.h + leaving this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. ++*/ + -+ */ ++/* $Id: apc_debug.c 307048 2011-01-03 23:53:17Z kalle $ */ ++#include "apc.h" ++#include ++#include "zend.h" ++#include "zend_compile.h" + -+/* $Id: apc_lock.h,v 3.20 2007/01/29 07:39:02 shire Exp $ */ ++#if defined(__DEBUG_APC__) + -+#ifndef APC_LOCK -+#define APC_LOCK ++/* keep track of vld_dump_oparray() signature */ ++typedef void (*vld_dump_f) (zend_op_array * TSRMLS_DC); + -+#include "apc_sem.h" -+#include "apc_fcntl.h" -+#include "apc_pthreadmutex.h" -+#include "apc_futex.h" -+#include "apc_spin.h" -+#ifdef HAVE_CONFIG_H -+#include +#endif + -+#ifdef TSRM_LOCKS -+#define RDLOCK_AVAILABLE 0 -+#define NONBLOCKING_LOCK_AVAILABLE 0 -+/* quick & dirty: use TSRM mutex locks for now */ -+#define apc_lck_create(a,b,c,d) d=(int)tsrm_mutex_alloc() -+#define apc_lck_destroy(a) tsrm_mutex_free((MUTEX_T)a) -+#define apc_lck_lock(a) tsrm_mutex_lock((MUTEX_T)a) -+#define apc_lck_rdlock(a) tsrm_mutex_lock((MUTEX_T)a) -+#define apc_lck_unlock(a) tsrm_mutex_unlock((MUTEX_T)a) -+#elif defined(APC_SEM_LOCKS) -+#define RDLOCK_AVAILABLE 0 -+#define NONBLOCKING_LOCK_AVAILABLE 0 -+#define apc_lck_t int -+#define apc_lck_create(a,b,c,d) d=apc_sem_create(NULL,(b),(c)) -+#define apc_lck_destroy(a) apc_sem_destroy(a) -+#define apc_lck_lock(a) apc_sem_lock(a) -+#define apc_lck_rdlock(a) apc_sem_lock(a) -+#define apc_lck_unlock(a) apc_sem_unlock(a) -+#elif defined(APC_PTHREADMUTEX_LOCKS) -+#define RDLOCK_AVAILABLE 0 -+#define NONBLOCKING_LOCK_AVAILABLE 1 -+#define apc_lck_t pthread_mutex_t -+#define apc_lck_create(a,b,c,d) apc_pthreadmutex_create((pthread_mutex_t*)&d) -+#define apc_lck_destroy(a) apc_pthreadmutex_destroy(&a) -+#define apc_lck_lock(a) apc_pthreadmutex_lock(&a) -+#define apc_lck_nb_lock(a) apc_pthreadmutex_nonblocking_lock(&a) -+#define apc_lck_rdlock(a) apc_pthreadmutex_lock(&a) -+#define apc_lck_unlock(a) apc_pthreadmutex_unlock(&a) -+#elif defined(APC_FUTEX_LOCKS) -+#define NONBLOCKING_LOCK_AVAILABLE 1 -+#define apc_lck_t int -+#define apc_lck_create(a,b,c,d) d=apc_futex_create() -+#define apc_lck_destroy(a) apc_futex_destroy(&a) -+#define apc_lck_lock(a) apc_futex_lock(&a) -+#define apc_lck_nb_lock(a) apc_futex_nonblocking_lock(&a) -+#define apc_lck_rdlock(a) apc_futex_lock(&a) -+#define apc_lck_unlock(a) apc_futex_unlock(&a) -+#elif defined(APC_SPIN_LOCKS) -+#define NONBLOCKING_LOCK_AVAILABLE APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE -+#define apc_lck_t slock_t -+#define apc_lck_create(a,b,c,d) apc_slock_create((slock_t*)&(d)) -+#define apc_lck_destroy(a) apc_slock_destroy(&a) -+#define apc_lck_lock(a) apc_slock_lock(&a) -+#define apc_lck_nb_lock(a) apc_slock_nonblocking_lock(&a) -+#define apc_lck_rdlock(a) apc_slock_lock(&a) -+#define apc_lck_unlock(a) apc_slock_unlock(&a) -+#else -+#define RDLOCK_AVAILABLE 1 ++void dump(zend_op_array *op_array TSRMLS_DC) ++{ ++#if defined(__DEBUG_APC__) ++ vld_dump_f dump_op_array; ++ DL_HANDLE handle = NULL; ++ +#ifdef PHP_WIN32 -+#define NONBLOCKING_LOCK_AVAILABLE 0 -+#else -+#define NONBLOCKING_LOCK_AVAILABLE 1 ++ handle = GetModuleHandle(NULL); ++ ++ if (!handle) { ++ apc_warning("unable to fetch current module handle." TSRMLS_CC); ++ } +#endif -+#define apc_lck_t int -+#define apc_lck_create(a,b,c,d) d=apc_fcntl_create((a)) -+#define apc_lck_destroy(a) apc_fcntl_destroy(a) -+#define apc_lck_lock(a) apc_fcntl_lock(a) -+#define apc_lck_nb_lock(a) apc_fcntl_nonblocking_lock(a) -+#define apc_lck_rdlock(a) apc_fcntl_rdlock(a) -+#define apc_lck_unlock(a) apc_fcntl_unlock(a) ++ ++ dump_op_array = (vld_dump_f) DL_FETCH_SYMBOL(handle, "vld_dump_oparray"); ++ ++#ifdef PHP_WIN32 ++ DL_UNLOAD(handle); +#endif + ++ if(dump_op_array) { ++ dump_op_array(op_array TSRMLS_CC); ++ ++ return; ++ } ++ ++ apc_warning("vld is not installed or something even worse." TSRMLS_CC); +#endif -Index: php-5.2.3/ext/apc/apc_main.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_main.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,681 @@ ++} +diff -Naur a/ext/apc/apc_debug.h b/ext/apc/apc_debug.h +--- a/ext/apc/apc_debug.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_debug.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -6019,7 +5909,6 @@ Index: php-5.2.3/ext/apc/apc_main.c + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | -+ | Rasmus Lerdorf | + | Arun C. Murthy | + | Gopal Vijayaraghavan | + +----------------------------------------------------------------------+ @@ -6031,670 +5920,479 @@ Index: php-5.2.3/ext/apc/apc_main.c + leaving this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. ++*/ + -+ */ -+ -+/* $Id: apc_main.c,v 3.97 2007/03/22 16:03:59 gopalv Exp $ */ -+ -+#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 "SAPI.h" -+#if PHP_API_VERSION <= 20020918 -+#if HAVE_APACHE -+#ifdef APC_PHP4_STAT -+#undef XtOffsetOf -+#include "httpd.h" -+#endif -+#endif -+#endif -+ -+/* {{{ module variables */ ++void dump(zend_op_array * TSRMLS_DC); +diff -Naur a/ext/apc/apc_fcntl.c b/ext/apc/apc_fcntl.c +--- a/ext/apc/apc_fcntl.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_fcntl.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,123 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: George Schlossnagle | ++ | Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ + -+/* 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; ++ 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. + -+/* {{{ 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; -+} -+/* }}} */ ++/* $Id: apc_fcntl.c 307048 2011-01-03 23:53:17Z kalle $ */ + -+/* {{{ install_function */ -+static int install_function(apc_function_t fn TSRMLS_DC) -+{ -+ int status = -+ zend_hash_add(EG(function_table), -+ fn.name, -+ fn.name_len+1, -+ apc_copy_function_for_execution(fn.function), -+ sizeof(fn.function[0]), -+ NULL); ++#include "apc.h" + -+ if (status == FAILURE) { -+ /* apc_eprint("Cannot redeclare %s()", fn.name); */ -+ } ++#ifdef APC_FCNTL_LOCKS + -+ return status; -+} -+/* }}} */ ++#include "apc_fcntl.h" ++#include ++#include + -+/* {{{ install_class */ -+static int install_class(apc_class_t cl TSRMLS_DC) ++int apc_fcntl_create(const char* pathname TSRMLS_DC) +{ -+ zend_class_entry* class_entry = cl.class_entry; -+ zend_class_entry* parent = NULL; -+ int status; -+#ifdef ZEND_ENGINE_2 -+ zend_class_entry** allocated_ce = NULL; -+#endif -+ -+ -+ /* 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; ++ int fd; ++ if(pathname == NULL) { ++ char lock_path[] = "/tmp/.apc.XXXXXX"; ++ mktemp(lock_path); ++ fd = open(lock_path, O_RDWR|O_CREAT, 0666); ++ if(fd > 0 ) { ++ unlink(lock_path); ++ return fd; ++ } else { ++ apc_error("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:" TSRMLS_CC, lock_path); ++ return -1; + } + } -+ -+#ifdef ZEND_ENGINE_2 -+ /* -+ * XXX: We need to free this somewhere... -+ */ -+ allocated_ce = apc_php_malloc(sizeof(zend_class_entry*)); -+ -+ if(!allocated_ce) { -+ return FAILURE; ++ fd = open(pathname, O_RDWR|O_CREAT, 0666); ++ if(fd > 0 ) { ++ unlink(pathname); ++ return fd; + } ++ apc_error("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:" TSRMLS_CC, pathname); ++ return -1; ++} + -+ *allocated_ce = -+#endif -+ class_entry = -+ apc_copy_class_entry_for_execution(cl.class_entry, -+ cl.is_derived); ++void apc_fcntl_destroy(int fd) ++{ ++ close(fd); ++} + ++static int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len) ++{ ++ int ret; ++ struct flock lock; + -+ /* restore parent class pointer for compile-time inheritance */ -+ if (cl.parent_name != NULL) { -+#ifdef ZEND_ENGINE_2 -+ zend_class_entry** parent_ptr = NULL; -+ /* -+ * zend_lookup_class has to be due to presence of __autoload, -+ * just looking up the EG(class_table) is not enough in php5! -+ * Even more dangerously, thanks to __autoload and people using -+ * class names as filepaths for inclusion, this has to be case -+ * sensitive. zend_lookup_class automatically does a case_fold -+ * internally, but passes the case preserved version to __autoload. -+ * Aside: Do NOT pass *strlen(cl.parent_name)+1* because -+ * zend_lookup_class does it internally anyway! -+ */ -+ status = zend_lookup_class(cl.parent_name, -+ strlen(cl.parent_name), -+ &parent_ptr TSRMLS_CC); -+#else -+ status = zend_hash_find(EG(class_table), -+ cl.parent_name, -+ strlen(cl.parent_name)+1, -+ (void**) &parent); -+#endif -+ if (status == FAILURE) { -+ if(APCG(report_autofilter)) { -+ apc_wprint("Dynamic inheritance detected for class %s", cl.name); -+ } -+ class_entry->parent = NULL; -+ return status; -+ } -+ else { -+#ifdef ZEND_ENGINE_2 -+ parent = *parent_ptr; -+#endif -+ class_entry->parent = parent; -+#ifdef ZEND_ENGINE_2 -+ zend_do_inheritance(class_entry, parent TSRMLS_CC); -+#else -+ zend_do_inheritance(class_entry, parent); -+#endif -+ } ++ lock.l_type = type; ++ lock.l_start = offset; ++ lock.l_whence = whence; ++ lock.l_len = len; ++ lock.l_pid = 0; + ++ do { ret = fcntl(fd, cmd, &lock) ; } ++ while(ret < 0 && errno == EINTR); ++ return(ret); ++} + ++void apc_fcntl_lock(int fd TSRMLS_DC) ++{ ++ if(lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) { ++ apc_error("apc_fcntl_lock failed:" TSRMLS_CC); + } -+ -+#ifdef ZEND_ENGINE_2 -+ status = zend_hash_add(EG(class_table), -+ cl.name, -+ cl.name_len+1, -+ allocated_ce, -+ sizeof(zend_class_entry*), -+ NULL); -+#else -+ status = zend_hash_add(EG(class_table), -+ cl.name, -+ cl.name_len+1, -+ class_entry, -+ sizeof(zend_class_entry), -+ NULL); -+#endif -+ -+ if (status == FAILURE) { -+ apc_eprint("Cannot redeclare class %s", cl.name); -+ } -+ return status; +} -+/* }}} */ + -+/* {{{ uninstall_class */ -+static int uninstall_class(apc_class_t cl TSRMLS_DC) ++void apc_fcntl_rdlock(int fd TSRMLS_DC) +{ -+ int status; -+ -+#ifdef ZEND_ENGINE_2 -+ status = zend_hash_del(EG(class_table), -+ cl.name, -+ cl.name_len+1); -+#else -+ status = zend_hash_del(EG(class_table), -+ cl.name, -+ cl.name_len+1); -+#endif -+ if (status == FAILURE) { -+ apc_eprint("Cannot delete class %s", cl.name); -+ } -+ return status; ++ if(lock_reg(fd, F_SETLKW, F_RDLCK, 0, SEEK_SET, 0) < 0) { ++ apc_error("apc_fcntl_rdlock failed:" TSRMLS_CC); ++ } +} -+/* }}} */ + -+/* {{{ compare_file_handles */ -+static int compare_file_handles(void* a, void* b) ++zend_bool apc_fcntl_nonblocking_lock(int fd TSRMLS_DC) +{ -+ zend_file_handle* fh1 = (zend_file_handle*)a; -+ zend_file_handle* fh2 = (zend_file_handle*)b; -+ return (fh1->type == fh2->type && -+ fh1->filename == fh2->filename && -+ fh1->opened_path == fh2->opened_path); ++ if(lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0) { ++ if(errno==EACCES||errno==EAGAIN) return 0; ++ else apc_error("apc_fcntl_lock failed:" TSRMLS_CC); ++ } ++ return 1; +} -+/* }}} */ + -+/* {{{ cached_compile */ -+static zend_op_array* cached_compile(zend_file_handle* h, -+ int type TSRMLS_DC) ++void apc_fcntl_unlock(int fd TSRMLS_DC) +{ -+ apc_cache_entry_t* cache_entry; -+ int i, ii; ++ if(lock_reg(fd, F_SETLKW, F_UNLCK, 0, SEEK_SET, 0) < 0) { ++ apc_error("apc_fcntl_unlock failed:" TSRMLS_CC); ++ } ++} + -+ cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack)); -+ assert(cache_entry != NULL); ++#endif /* APC_FCNTL_LOCKS */ + -+ if (cache_entry->data.file.classes) { -+ for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { -+ if(install_class(cache_entry->data.file.classes[i] TSRMLS_CC) == FAILURE) { -+ goto default_compile; -+ } -+ } -+ } ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_fcntl.h b/ext/apc/apc_fcntl.h +--- a/ext/apc/apc_fcntl.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_fcntl.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,50 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: George Schlossnagle | ++ | Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ + -+ if (cache_entry->data.file.functions) { -+ for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) { -+ install_function(cache_entry->data.file.functions[i] TSRMLS_CC); -+ } -+ } ++ 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. + -+ return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array TSRMLS_CC); ++ */ + -+default_compile: ++/* $Id: apc_fcntl.h 307048 2011-01-03 23:53:17Z kalle $ */ + -+ cache_entry->autofiltered = 1; -+ if(APCG(report_autofilter)) { -+ apc_wprint("Autofiltering %s", h->opened_path); -+ } ++#ifndef APC_FCNTL_H ++#define APC_FCNTL_H + -+ 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 */ + -+ /* cannot free up cache data yet, it maybe in use */ -+ -+ zend_llist_del_element(&CG(open_files), h, compare_file_handles); /* XXX: kludge */ -+ -+ h->type = ZEND_HANDLE_FILENAME; -+ -+ return old_compile_file(h, type TSRMLS_CC); -+} -+/* }}} */ ++extern int apc_fcntl_create(const char* pathname TSRMLS_DC); ++extern void apc_fcntl_destroy(int fd); ++extern void apc_fcntl_lock(int fd TSRMLS_DC); ++extern void apc_fcntl_rdlock(int fd TSRMLS_DC); ++extern void apc_fcntl_unlock(int fd TSRMLS_DC); ++extern unsigned char apc_fcntl_nonblocking_lock(int fd TSRMLS_DC); ++#endif + -+/* {{{ 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; -+ int num_functions, num_classes, ret; -+ zend_op_array* alloc_op_array; -+ apc_function_t* alloc_functions; -+ apc_class_t* alloc_classes; -+ time_t t; -+ char *path; -+ size_t mem_size; ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_fcntl_win32.c b/ext/apc/apc_fcntl_win32.c +--- a/ext/apc/apc_fcntl_win32.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_fcntl_win32.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,120 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: George Schlossnagle | ++ | Edin Kadribasic | ++ | Pierre Joye | ++ +----------------------------------------------------------------------+ + -+ if (!APCG(enabled) || (apc_cache_busy(apc_cache) && !APCG(localcache))) { -+ return old_compile_file(h, type TSRMLS_CC); -+ } ++ 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. + -+ /* check our regular expression filters */ -+ if (APCG(filters) && apc_compiled_filters) { -+ int ret = apc_regex_match_array(apc_compiled_filters, h->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); -+ } ++ All other licensing and usage conditions are those of the PHP Group. + -+#if PHP_API_VERSION <= 20041225 -+#if HAVE_APACHE && defined(APC_PHP4_STAT) -+ t = ((request_rec *)SG(server_context))->request_time; -+#else -+ t = time(0); -+#endif -+#else -+ t = sapi_get_request_time(TSRMLS_C); -+#endif ++ */ + -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"1. h->opened_path=[%s] h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename); -+#endif ++/* $Id: apc_fcntl_win32.c 309203 2011-03-14 06:47:16Z pajoye $ */ + -+ /* 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); -+ } ++#include "apc.h" ++#include "apc_fcntl.h" ++#include ++#include ++#include ++#include ++#include ++#include + -+ if(APCG(localcache)) { -+ /* search for the file in the local cache */ -+ cache_entry = apc_local_cache_find(APCG(lcache), key, t); -+ } else { -+ /* search for the file in the cache */ -+ cache_entry = apc_cache_find(apc_cache, key, t); ++int apc_fcntl_create(const char* pathname TSRMLS_DC) ++{ ++ char lock_file[MAXPATHLEN]; ++ HANDLE fd; ++ DWORD tmp_dirname_len; ++ char lock_filename_tpl[] = ".apc.XXXXXX"; ++ char *lock_filename; ++ ++ tmp_dirname_len = GetTempPath(MAXPATHLEN, lock_file); ++ if (!tmp_dirname_len) { ++ return -1; + } + -+ if (cache_entry != NULL && !cache_entry->autofiltered) { -+ int dummy = 1; -+ if (h->opened_path == NULL) { -+ h->opened_path = estrdup(cache_entry->data.file.filename); -+ } -+ zend_hash_add(&EG(included_files), h->opened_path, strlen(h->opened_path)+1, (void *)&dummy, sizeof(int), NULL); -+ zend_llist_add_element(&CG(open_files), h); /* XXX kludge */ -+ apc_stack_push(APCG(cache_stack), cache_entry); -+ return cached_compile(h, type TSRMLS_CC); -+ } -+ else if(cache_entry != NULL && cache_entry->autofiltered) { -+ /* nobody else is using this cache_entry */ -+ if(cache_entry->ref_count == 1) { -+ if(cache_entry->data.file.op_array) { -+ apc_free_op_array(cache_entry->data.file.op_array, apc_sma_free); -+ cache_entry->data.file.op_array = NULL; -+ } -+ if(cache_entry->data.file.functions) { -+ apc_free_functions(cache_entry->data.file.functions, apc_sma_free); -+ cache_entry->data.file.functions = NULL; -+ } -+ if(cache_entry->data.file.classes) { -+ apc_free_classes(cache_entry->data.file.classes, apc_sma_free); -+ cache_entry->data.file.classes = NULL; -+ } -+ } -+ /* We never push this into the cache_stack, so we have to do a release */ -+ apc_cache_release(apc_cache, cache_entry); -+ return old_compile_file(h, type TSRMLS_CC); ++ lock_filename = _mktemp(lock_filename_tpl); ++ if (lock_filename == NULL) { ++ return -1; + } -+ -+ if(apc_cache_busy(apc_cache) && APCG(localcache)) { -+ /* possibly local cache returned NULL because cache is busy */ -+ return old_compile_file(h, type TSRMLS_CC); -+ } + -+ /* 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 */ -+ op_array = old_compile_file(h, type TSRMLS_CC); -+ if (op_array == NULL) { -+ return NULL; -+ } -+ /* -+ * Basically this will cause a file only to be cached on a percentage -+ * of the attempts. This is to avoid cache slams when starting up a -+ * very busy server or when modifying files on a very busy live server. -+ * There is no point having many processes all trying to cache the same -+ * file at the same time. By introducing a chance of being cached -+ * we theoretically cut the cache slam problem by the given percentage. -+ * For example if apc.slam_defense is set to 66 then 2/3 of the attempts -+ * to cache an uncached file will be ignored. -+ */ -+ if(APCG(slam_defense)) { -+ if(APCG(slam_rand)==-1) { -+ APCG(slam_rand) = (int)(100.0*rand()/(RAND_MAX+1.0)); -+ } -+ if(APCG(slam_rand) < APCG(slam_defense)) { -+ return op_array; -+ } -+ } ++ snprintf(lock_file + tmp_dirname_len, MAXPATHLEN - tmp_dirname_len - 1, "%s", lock_filename); + -+ HANDLE_BLOCK_INTERRUPTIONS(); ++ fd = CreateFile(lock_file, ++ GENERIC_READ | GENERIC_WRITE, ++ FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_ALWAYS, ++ FILE_ATTRIBUTE_NORMAL, ++ NULL); + -+#if NONBLOCKING_LOCK_AVAILABLE -+ if(APCG(write_lock)) { -+ if(!apc_cache_write_lock(apc_cache)) { -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return op_array; -+ } ++ if (fd == INVALID_HANDLE_VALUE) { ++ apc_error("apc_fcntl_create: could not open %s" TSRMLS_CC, lock_file); ++ return -1; + } -+#endif + -+ mem_size = 0; -+ APCG(mem_size_ptr) = &mem_size; -+ if(!(alloc_op_array = apc_copy_op_array(NULL, op_array, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ APCG(mem_size_ptr) = NULL; -+#if NONBLOCKING_LOCK_AVAILABLE -+ if(APCG(write_lock)) { -+ apc_cache_write_unlock(apc_cache); -+ } -+#endif -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return op_array; -+ } -+ -+ if(!(alloc_functions = apc_copy_new_functions(num_functions, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { -+ apc_free_op_array(alloc_op_array, apc_sma_free); -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ APCG(mem_size_ptr) = NULL; -+#if NONBLOCKING_LOCK_AVAILABLE -+ if(APCG(write_lock)) { -+ apc_cache_write_unlock(apc_cache); -+ } -+#endif -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return op_array; -+ } -+ if(!(alloc_classes = apc_copy_new_classes(op_array, num_classes, apc_sma_malloc, apc_sma_free TSRMLS_CC))) { -+ apc_free_op_array(alloc_op_array, apc_sma_free); -+ apc_free_functions(alloc_functions, apc_sma_free); -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ APCG(mem_size_ptr) = NULL; -+#if NONBLOCKING_LOCK_AVAILABLE -+ if(APCG(write_lock)) { -+ apc_cache_write_unlock(apc_cache); -+ } -+#endif -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return op_array; -+ } ++ return (int)fd; ++} + -+ path = h->opened_path; -+ if(!path) path=h->filename; ++void apc_fcntl_destroy(int fd) ++{ ++ CloseHandle((HANDLE)fd); ++} + -+#ifdef __DEBUG_APC__ -+ fprintf(stderr,"2. h->opened_path=[%s] h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename); -+#endif ++void apc_fcntl_lock(int fd TSRMLS_DC) ++{ ++ OVERLAPPED offset = {0, 0, 0, 0, NULL}; + -+ if(!(cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes))) { -+ apc_free_op_array(alloc_op_array, apc_sma_free); -+ apc_free_functions(alloc_functions, apc_sma_free); -+ apc_free_classes(alloc_classes, apc_sma_free); -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ APCG(mem_size_ptr) = NULL; -+#if NONBLOCKING_LOCK_AVAILABLE -+ if(APCG(write_lock)) { -+ apc_cache_write_unlock(apc_cache); -+ } -+#endif -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return op_array; ++ if (!LockFileEx((HANDLE)fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &offset)) { ++ apc_error("apc_fcntl_lock failed errno:%d" TSRMLS_CC, GetLastError()); + } -+ APCG(mem_size_ptr) = NULL; -+ cache_entry->mem_size = mem_size; ++} + -+ if ((ret = apc_cache_insert(apc_cache, key, cache_entry, t)) != 1) { -+ apc_cache_free_entry(cache_entry); -+ if(ret==-1) { -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ } -+ } ++void apc_fcntl_rdlock(int fd TSRMLS_DC) ++{ ++ OVERLAPPED offset = {0, 0, 0, 0, NULL}; + -+#if NONBLOCKING_LOCK_AVAILABLE -+ if(APCG(write_lock)) { -+ apc_cache_write_unlock(apc_cache); ++ if (!LockFileEx((HANDLE)fd, 0, 0, 1, 0, &offset)) { ++ apc_error("apc_fcntl_rdlock failed errno:%d" TSRMLS_CC, GetLastError()); + } -+#endif -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ -+ return op_array; +} -+/* }}} */ -+ -+/* {{{ module init and shutdown */ + -+int apc_module_init(int module_number TSRMLS_DC) ++void apc_fcntl_unlock(int fd TSRMLS_DC) +{ -+ /* apc initialization */ -+#if APC_MMAP -+ apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, APCG(mmap_file_mask)); -+#else -+ apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, NULL); -+#endif -+ apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl)); -+ apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl)); -+ -+ apc_compiled_filters = apc_regex_compile_array(APCG(filters)); -+ -+ /* 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); ++ OVERLAPPED offset = {0, 0, 0, 0, NULL}; + -+ APCG(initialized) = 1; -+ return 0; ++ if (!UnlockFileEx((HANDLE)fd, 0, 1, 0, &offset)) { ++ DWORD error_code = GetLastError(); ++ /* Ignore already unlocked error */ ++ if (error_code != ERROR_NOT_LOCKED) { ++ apc_error("apc_fcntl_unlock failed errno:%d" TSRMLS_CC, error_code); ++ } ++ } +} + -+int apc_module_shutdown(TSRMLS_D) -+{ -+ if (!APCG(initialized)) -+ 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 ++ */ +diff -Naur a/ext/apc/apc_globals.h b/ext/apc/apc_globals.h +--- a/ext/apc/apc_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_globals.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,152 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | George Schlossnagle | ++ | Rasmus Lerdorf | ++ | Arun C. Murthy | ++ | Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ + -+ /* restore compilation */ -+ zend_compile_file = old_compile_file; ++ 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. + -+ /* -+ * 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); -+ } ++ All other licensing and usage conditions are those of the PHP Group. + -+ apc_cache_destroy(apc_cache); -+ apc_cache_destroy(apc_user_cache); -+ apc_sma_cleanup(); ++ */ + -+ APCG(initialized) = 0; -+ return 0; -+} ++/* $Id: apc_globals.h 307215 2011-01-07 09:54:00Z gopalv $ */ + -+/* }}} */ ++#ifndef APC_GLOBALS_H ++#define APC_GLOBALS_H + -+/* {{{ process init and shutdown */ -+int apc_process_init(int module_number TSRMLS_DC) -+{ -+ int minttl = (APCG(gc_ttl) > APCG(ttl) ? APCG(ttl) : APCG(gc_ttl))/2; -+ int size = APCG(localcache_size); -+ if(APCG(initialized) && APCG(localcache)) { -+ /* TTL is 2 mins by default */ -+ APCG(lcache) = apc_local_cache_create(apc_cache, size, minttl ? minttl : 120); -+ } -+ return 0; -+} ++#include "apc_cache.h" ++#include "apc_stack.h" ++#include "apc_php.h" ++#include "apc_main.h" + -+int apc_process_shutdown(TSRMLS_D) -+{ -+ if(APCG(initialized) && APCG(localcache) && APCG(lcache)) { -+ apc_local_cache_destroy(APCG(lcache)); -+ APCG(lcache) = NULL; -+ } -+ return 0; -+} ++/* {{{ struct apc_rfc1867_data */ ++ ++typedef struct _apc_rfc1867_data apc_rfc1867_data; ++ ++struct _apc_rfc1867_data { ++ char tracking_key[64]; ++ int key_length; ++ size_t content_length; ++ char filename[128]; ++ char name[64]; ++ char *temp_filename; ++ int cancel_upload; ++ double start_time; ++ size_t bytes_processed; ++ size_t prev_bytes_processed; ++ int update_freq; ++ double rate; ++ int started; ++}; +/* }}} */ + -+/* {{{ request init and shutdown */ + -+int apc_request_init(TSRMLS_D) -+{ -+ apc_stack_clear(APCG(cache_stack)); -+ APCG(slam_rand) = -1; -+ APCG(copied_zvals) = NULL; -+ return 0; -+} -+ -+int apc_request_shutdown(TSRMLS_D) -+{ -+ apc_deactivate(TSRMLS_C); -+ return 0; -+} -+ -+/* }}} */ ++ZEND_BEGIN_MODULE_GLOBALS(apc) ++ /* configuration parameters */ ++ zend_bool enabled; /* if true, apc is enabled (defaults to true) */ ++ long shm_segments; /* number of shared memory segments to use */ ++ long shm_size; /* size of each shared memory segment (in MB) */ ++ long num_files_hint; /* parameter to apc_cache_create */ ++ long user_entries_hint; ++ long gc_ttl; /* parameter to apc_cache_create */ ++ long ttl; /* parameter to apc_cache_create */ ++ long user_ttl; ++#if APC_MMAP ++ char *mmap_file_mask; /* mktemp-style file-mask to pass to mmap */ ++#endif ++ char** filters; /* array of regex filters that prevent caching */ ++ void* compiled_filters; /* compiled regex filters */ + -+/* {{{ apc_deactivate */ -+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); -+#ifdef ZEND_ENGINE_2 -+ zend_class_entry** pzce = NULL; ++ /* module variables */ ++ zend_bool initialized; /* true if module was initialized */ ++ apc_stack_t* cache_stack; /* the stack of cached executable code */ ++ zend_bool cache_by_default; /* true if files should be cached unless filtered out */ ++ /* false if files should only be cached if filtered in */ ++ long file_update_protection; /* Age in seconds before a file is eligible to be cached - 0 to disable */ ++ zend_bool enable_cli; /* Flag to override turning APC off for CLI */ ++ long max_file_size; /* Maximum size of file, in bytes that APC will be allowed to cache */ ++ zend_bool fpstat; /* true if fullpath includes should be stat'ed */ ++ zend_bool canonicalize; /* true if relative paths should be canonicalized in no-stat mode */ ++ zend_bool stat_ctime; /* true if ctime in addition to mtime should be checked */ ++ zend_bool write_lock; /* true for a global write lock */ ++ zend_bool slam_defense; /* true for user cache slam defense */ ++ zend_bool report_autofilter; /* true for auto-filter warnings */ ++ zend_bool include_once; /* Override the ZEND_INCLUDE_OR_EVAL opcode handler to avoid pointless fopen()s [still experimental] */ ++ apc_optimize_function_t apc_optimize_function; /* optimizer function callback */ ++#ifdef MULTIPART_EVENT_FORMDATA ++ zend_bool rfc1867; /* Flag to enable rfc1867 handler */ ++ char* rfc1867_prefix; /* Key prefix */ ++ char* rfc1867_name; /* Name of hidden field to activate upload progress/key suffix */ ++ double rfc1867_freq; /* Update frequency as percentage or bytes */ ++ long rfc1867_ttl; /* TTL for rfc1867 entries */ ++ apc_rfc1867_data rfc1867_data;/* Per-request data */ +#endif -+ -+ apc_cache_entry_t* cache_entry = -+ (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack)); ++ HashTable copied_zvals; /* my_copy recursion detection list */ ++ zend_bool force_file_update; /* force files to be updated during apc_compile_file */ ++ char canon_path[MAXPATHLEN]; /* canonical path for key data */ ++#ifdef APC_FILEHITS ++ zval *filehits; /* Files that came from the cache for this request */ ++#endif ++ zend_bool coredump_unmap; /* Trap signals that coredump and unmap shared memory */ ++ apc_cache_t *current_cache; /* current cache being modified/read */ ++ char *preload_path; ++ zend_bool file_md5; /* record md5 hash of files */ ++ void *apc_bd_alloc_ptr; /* bindump alloc() ptr */ ++ void *apc_bd_alloc_ubptr; /* bindump alloc() upper bound ptr */ ++ HashTable apc_bd_alloc_list; /* bindump alloc() ptr list */ ++ zend_bool use_request_time; /* use the SAPI request start time for TTL */ ++ zend_bool lazy_functions; /* enable/disable lazy function loading */ ++ HashTable *lazy_function_table; /* lazy function entry table */ ++ zend_bool lazy_classes; /* enable/disable lazy class loading */ ++ HashTable *lazy_class_table; /* lazy class entry table */ ++#ifdef ZEND_ENGINE_2_4 ++ long shm_strings_buffer; ++#endif ++ char *serializer_name; /* the serializer config option */ ++ apc_serializer_t *serializer;/* the actual serializer in use */ ++ZEND_END_MODULE_GLOBALS(apc) + -+ 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); -+ } -+ } ++/* (the following declaration is defined in php_apc.c) */ ++ZEND_EXTERN_MODULE_GLOBALS(apc) + -+ if (cache_entry->data.file.classes) { -+ for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) { -+#ifdef ZEND_ENGINE_2 -+ centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */ ++#ifdef ZTS ++# define APCG(v) TSRMG(apc_globals_id, zend_apc_globals *, v) ++#else ++# define APCG(v) (apc_globals.v) +#endif -+ 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; -+ } + -+#ifdef ZEND_ENGINE_2 -+ zce = *pzce; ++/* True globals */ ++extern apc_cache_t* apc_cache; /* the global compiler cache */ ++extern apc_cache_t* apc_user_cache; /* the global user content cache */ ++extern void* apc_compiled_filters; /* compiled filters */ ++ +#endif -+ 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); -+ } -+ } -+ apc_cache_release(apc_cache, cache_entry); -+ } -+ if(APCG(localcache)) { -+ apc_local_cache_cleanup(APCG(lcache)); -+ } -+} -+/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_main.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_main.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,67 @@ +diff -Naur a/ext/apc/apc.h b/ext/apc/apc.h +--- a/ext/apc/apc.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,136 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -6721,31 +6419,100 @@ Index: php-5.2.3/ext/apc/apc_main.h + + */ + -+/* $Id: apc_main.h,v 3.9 2007/02/28 01:15:18 gopalv Exp $ */ ++/* $Id: apc.h 307264 2011-01-08 13:20:20Z gopalv $ */ + -+#ifndef APC_MAIN_H -+#define APC_MAIN_H ++#ifndef APC_H ++#define APC_H + +/* -+ * This module provides the primary interface between PHP and APC. ++ * This module defines utilities and helper functions used elsewhere in APC. + */ + -+extern int apc_module_init(int module_number TSRMLS_DC); -+extern int apc_module_shutdown(TSRMLS_D); -+extern int apc_process_init(int module_number TSRMLS_DC); -+extern int apc_process_shutdown(TSRMLS_D); -+extern int apc_request_init(TSRMLS_D); -+extern int apc_request_shutdown(TSRMLS_D); ++/* Commonly needed C library headers. */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+/* -+ * apc_deactivate is called by the PHP interpreter when an "exception" is -+ * raised (e.g., a call to the exit function) that unwinds the execution -+ * stack. -+ */ -+extern void apc_deactivate(); ++/* UNIX headers (needed for struct stat) */ ++#include ++#include ++#ifndef PHP_WIN32 ++#include ++#endif ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include "php.h" ++#include "main/php_streams.h" ++ ++/* typedefs for extensible memory allocators */ ++typedef void* (*apc_malloc_t)(size_t TSRMLS_DC); ++typedef void (*apc_free_t) (void * TSRMLS_DC); ++ ++/* wrappers for memory allocation routines */ ++extern void* apc_emalloc(size_t n TSRMLS_DC); ++extern void* apc_erealloc(void* p, size_t n TSRMLS_DC); ++extern void apc_efree(void* p TSRMLS_DC); ++extern char* apc_estrdup(const char* s TSRMLS_DC); ++extern void* apc_xstrdup(const char* s, apc_malloc_t f TSRMLS_DC); ++extern void* apc_xmemcpy(const void* p, size_t n, apc_malloc_t f TSRMLS_DC); ++ ++/* console display functions */ ++extern void apc_error(const char *format TSRMLS_DC, ...); ++extern void apc_warning(const char *format TSRMLS_DC, ...); ++extern void apc_notice(const char *format TSRMLS_DC, ...); ++extern void apc_debug(const char *format TSRMLS_DC, ...); ++ ++/* string and text manipulation */ ++extern char* apc_append(const char* s, const char* t TSRMLS_DC); ++extern char* apc_substr(const char* s, int start, int length TSRMLS_DC); ++extern char** apc_tokenize(const char* s, char delim TSRMLS_DC); ++ ++/* filesystem functions */ ++ ++typedef struct apc_fileinfo_t ++{ ++ char *fullpath; ++ char path_buf[MAXPATHLEN]; ++ php_stream_statbuf st_buf; ++} apc_fileinfo_t; ++ ++extern int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo TSRMLS_DC); ++ ++/* regular expression wrapper functions */ ++extern void* apc_regex_compile_array(char* patterns[] TSRMLS_DC); ++extern void apc_regex_destroy_array(void* p TSRMLS_DC); ++extern int apc_regex_match_array(void* p, const char* input); ++ ++/* apc_crc32: returns the CRC-32 checksum of the first len bytes in buf */ ++extern unsigned int apc_crc32(const char* buf, int len); ++ ++/* apc_flip_hash flips keys and values for faster searching */ ++extern HashTable* apc_flip_hash(HashTable *hash); ++ ++#define APC_NEGATIVE_MATCH 1 ++#define APC_POSITIVE_MATCH 2 + ++#define apc_time() \ ++ (APCG(use_request_time) ? (time_t) sapi_get_request_time(TSRMLS_C) : time(0)); + -+extern const char* apc_version(); ++#if defined(__GNUC__) ++# define APC_UNUSED __attribute__((unused)) ++# define APC_USED __attribute__((used)) ++# define APC_ALLOC __attribute__((malloc)) ++# define APC_HOTSPOT __attribute__((hot)) ++#else ++# define APC_UNUSED ++# define APC_USED ++# define APC_ALLOC ++# define APC_HOTSPOT ++#endif + +#endif + @@ -6754,19 +6521,18 @@ Index: php-5.2.3/ext/apc/apc_main.h + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_mmap.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_mmap.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,137 @@ +diff -Naur a/ext/apc/apc_iterator.c b/ext/apc/apc_iterator.c +--- a/ext/apc/apc_iterator.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_iterator.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,741 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -6776,1457 +6542,6703 @@ Index: php-5.2.3/ext/apc/apc_mmap.c + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ -+ | Authors: Rasmus Lerdorf | ++ | Authors: Brian Shire | + +----------------------------------------------------------------------+ + -+ 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_mmap.c,v 3.5 2006/03/12 00:31:45 rasmus Exp $ */ ++/* $Id: apc_iterator.c 324326 2012-03-18 13:19:50Z pajoye $ */ + -+#include "apc.h" ++#include "php_apc.h" ++#include "apc_iterator.h" ++#include "apc_cache.h" ++#include "apc_zend.h" + -+#if APC_MMAP ++#include "ext/standard/md5.h" + -+#include -+#include -+#include ++#include "zend_interfaces.h" + -+/* -+ * Some operating systems (like FreeBSD) have a MAP_NOSYNC flag that -+ * tells whatever update daemons might be running to not flush dirty -+ * vm pages to disk unless absolutely necessary. My guess is that -+ * most systems that don't have this probably default to only synching -+ * to disk when absolutely necessary. -+ */ -+#ifndef MAP_NOSYNC -+#define MAP_NOSYNC 0 -+#endif ++zend_class_entry *apc_iterator_ce; ++zend_object_handlers apc_iterator_object_handlers; + -+void *apc_mmap(char *file_mask, int size) -+{ -+ void* shmaddr; /* the shared memory address */ + -+ /* If no filename was provided, do an anonymous mmap */ -+ if(!file_mask || (file_mask && !strlen(file_mask))) { -+ shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); ++/* {{{ apc_iterator_item */ ++static apc_iterator_item_t* apc_iterator_item_ctor(apc_iterator_t *iterator, slot_t **slot_pp TSRMLS_DC) { ++ zval *zvalue; ++ char md5str[33]; ++ slot_t *slot = *slot_pp; ++ apc_context_t ctxt = {0, }; ++ apc_iterator_item_t *item = ecalloc(1, sizeof(apc_iterator_item_t)); ++ ++ if (slot->key.type == APC_CACHE_KEY_FILE) { ++ /* keys should be unique and with stat=1 we could have multiple files with the same name, so use ' ' instead */ ++#ifdef PHP_WIN32 ++ item->key_len = spprintf(&item->key, 0, "%I64d %I64d", slot->key.data.file.device, slot->key.data.file.inode); ++#else ++ item->key_len = spprintf(&item->key, 0, "%ld %ld", (ulong)slot->key.data.file.device, (ulong)slot->key.data.file.inode); ++#endif ++ item->filename_key = estrdup(slot->value->data.file.filename); ++ } else if (slot->key.type == APC_CACHE_KEY_USER) { ++ item->key = estrndup((char*)slot->key.data.user.identifier, slot->key.data.user.identifier_len); ++ item->key_len = slot->key.data.user.identifier_len; ++ item->filename_key = item->key; ++ } else if (slot->key.type == APC_CACHE_KEY_FPFILE) { ++ item->key = estrndup((char*)slot->key.data.fpfile.fullpath, slot->key.data.fpfile.fullpath_len); ++ item->key_len = slot->key.data.fpfile.fullpath_len; ++ item->filename_key = item->key; + } else { -+ int fd; ++ apc_error("Internal error, invalid entry type." TSRMLS_CC); ++ } + -+ /* -+ * If the filemask contains .shm we try to do a POSIX-compliant shared memory -+ * backed mmap which should avoid synchs on some platforms. At least on -+ * FreeBSD this implies MAP_NOSYNC and on Linux it is equivalent of mmap'ing -+ * a file in a mounted shmfs. For this to work on Linux you need to make sure -+ * you actually have shmfs mounted. Also on Linux, make sure the file_mask you -+ * pass in has a leading / and no other /'s. eg. /apc.shm.XXXXXX -+ * On FreeBSD these are mapped onto the regular filesystem so you can put whatever -+ * path you want here. -+ */ -+ if(strstr(file_mask,".shm")) { -+ mktemp(file_mask); -+ fd = shm_open(file_mask, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); -+ if(fd == -1) { -+ apc_eprint("apc_mmap: shm_open on %s failed:", file_mask); -+ return (void *)-1; -+ } -+ if (ftruncate(fd, size) < 0) { -+ close(fd); -+ shm_unlink(file_mask); -+ apc_eprint("apc_mmap: ftruncate failed:"); -+ return (void *)-1; -+ } -+ shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -+ shm_unlink(file_mask); -+ close(fd); ++ ALLOC_INIT_ZVAL(item->value); ++ array_init(item->value); ++ ++ if (APC_ITER_TYPE & iterator->format) { ++ if(slot->value->type == APC_CACHE_ENTRY_FILE) { ++ add_assoc_string(item->value, "type", "file", 1); ++ } else if(slot->value->type == APC_CACHE_ENTRY_USER) { ++ add_assoc_string(item->value, "type", "user", 1); + } -+ /* -+ * Support anonymous mmap through the /dev/zero interface as well -+ */ -+ else if(!strcmp(file_mask,"/dev/zero")) { -+ fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); -+ if(fd == -1) { -+ apc_eprint("apc_mmap: open on /dev/zero failed:"); -+ return (void *)-1; ++ } ++ if (APC_ITER_FILENAME & iterator->format) { ++ if(slot->value->type == APC_CACHE_ENTRY_FILE) { ++ if (slot->key.type == APC_CACHE_KEY_FILE) { ++ add_assoc_string(item->value, "filename", slot->value->data.file.filename, 1); ++ } else { /* APC_CACHE_FPFILE */ ++ add_assoc_string(item->value, "filename", (char*)slot->key.data.fpfile.fullpath, 1); + } -+ shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -+ close(fd); + } -+ /* -+ * Otherwise we do a normal filesystem mmap -+ */ -+ else { -+ fd = mkstemp(file_mask); -+ if(fd == -1) { -+ apc_eprint("apc_mmap: mkstemp on %s failed:", file_mask); -+ return (void *)-1; -+ } -+ if (ftruncate(fd, size) < 0) { -+ close(fd); -+ unlink(file_mask); -+ apc_eprint("apc_mmap: ftruncate failed:"); ++ } ++ if (APC_ITER_DEVICE & iterator->format) { ++ if(slot->key.type == APC_CACHE_KEY_FILE) { ++#ifdef PHP_WIN32 ++ char buf[20]; ++ sprintf(buf, "%I64d", slot->key.data.file.device); ++ add_assoc_string(item->value, "device", buf, 1); ++#else ++ add_assoc_long(item->value, "device", slot->key.data.file.device); ++#endif ++ } ++ } ++ if (APC_ITER_INODE & iterator->format) { ++ if(slot->key.type == APC_CACHE_KEY_FILE) { ++#ifdef PHP_WIN32 ++ char buf[20]; ++ sprintf(buf, "%I64d", slot->key.data.file.device); ++ add_assoc_string(item->value, "device", buf, 1); ++#else ++ add_assoc_long(item->value, "inode", slot->key.data.file.inode); ++#endif ++ } ++ } ++ if (APC_ITER_KEY & iterator->format) { ++ add_assoc_stringl(item->value, "key", item->key, (item->key_len - 1), 1); ++ } ++ if (APC_ITER_VALUE & iterator->format) { ++ if(slot->value->type == APC_CACHE_ENTRY_USER) { ++ ++ ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, NULL, NULL TSRMLS_CC); ++ ctxt.copy = APC_COPY_OUT_USER; ++ ++ MAKE_STD_ZVAL(zvalue); ++ apc_cache_fetch_zval(zvalue, slot->value->data.user.val, &ctxt TSRMLS_CC); ++ apc_pool_destroy(ctxt.pool TSRMLS_CC); ++ add_assoc_zval(item->value, "value", zvalue); ++ } ++ } ++ if (APC_ITER_MD5 & iterator->format) { ++ if(slot->value->type == APC_CACHE_ENTRY_FILE) { ++ if(APCG(file_md5) && slot->key.md5) { ++ make_digest(md5str, slot->key.md5); ++ add_assoc_string(item->value, "md5", md5str, 1); + } -+ shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOSYNC, fd, 0); -+ close(fd); -+ unlink(file_mask); + } + } -+ if((int)shmaddr == -1) { -+ apc_eprint("apc_mmap: mmap failed:"); ++ if (APC_ITER_NUM_HITS & iterator->format) { ++ add_assoc_long(item->value, "num_hits", slot->num_hits); ++ } ++ if (APC_ITER_MTIME & iterator->format) { ++ add_assoc_long(item->value, "mtime", slot->key.mtime); ++ } ++ if (APC_ITER_CTIME & iterator->format) { ++ add_assoc_long(item->value, "creation_time", slot->creation_time); + } -+ return shmaddr; ++ if (APC_ITER_DTIME & iterator->format) { ++ add_assoc_long(item->value, "deletion_time", slot->deletion_time); ++ } ++ if (APC_ITER_ATIME & iterator->format) { ++ add_assoc_long(item->value, "access_time", slot->access_time); ++ } ++ if (APC_ITER_REFCOUNT & iterator->format) { ++ add_assoc_long(item->value, "ref_count", slot->value->ref_count); ++ } ++ if (APC_ITER_MEM_SIZE & iterator->format) { ++ add_assoc_long(item->value, "mem_size", slot->value->mem_size); ++ } ++ if (APC_ITER_TTL & iterator->format) { ++ if(slot->value->type == APC_CACHE_ENTRY_USER) { ++ add_assoc_long(item->value, "ttl", slot->value->data.user.ttl); ++ } ++ } ++ ++ return item; +} ++/* }}} */ + -+void apc_unmap(void* shmaddr, int size) -+{ -+ munmap(shmaddr, size); ++/* {{{ apc_iterator_clone */ ++static zend_object_value apc_iterator_clone(zval *zobject TSRMLS_DC) { ++ zend_object_value value = {0}; ++ apc_error("APCIterator object cannot be cloned." TSRMLS_CC); ++ return value; +} ++/* }}} */ + -+#endif ++/* {{{ apc_iterator_item_dtor */ ++static void apc_iterator_item_dtor(apc_iterator_item_t *item) { ++ if (item->filename_key && item->filename_key != item->key) { ++ efree(item->filename_key); ++ } ++ if (item->key) { ++ efree(item->key); ++ } ++ if (item->value) { ++ zval_ptr_dtor(&item->value); ++ } ++ efree(item); ++} ++/* }}} */ + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc.php -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc.php 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,1313 @@ -+ | -+ | Rasmus Lerdorf | -+ | Ilia Alshanetsky | -+ +----------------------------------------------------------------------+ ++/* {{{ apc_iterator_destroy */ ++static void apc_iterator_destroy(void *object, zend_object_handle handle TSRMLS_DC) { ++ apc_iterator_t *iterator = (apc_iterator_t*)object; + -+ All other licensing and usage conditions are those of the PHP Group. ++ if (iterator->initialized == 0) { ++ return; ++ } ++ ++ while (apc_stack_size(iterator->stack) > 0) { ++ apc_iterator_item_dtor(apc_stack_pop(iterator->stack)); ++ } ++ if (iterator->regex) { ++ efree(iterator->regex); ++ } ++ if (iterator->search_hash) { ++ zend_hash_destroy(iterator->search_hash); ++ efree(iterator->search_hash); ++ } ++ iterator->initialized = 0; ++ ++} ++/* }}} */ ++ ++/* {{{ acp_iterator_free */ ++static void apc_iterator_free(void *object TSRMLS_DC) { ++ zend_object_std_dtor(object TSRMLS_CC); ++ efree(object); ++} ++/* }}} */ ++ ++/* {{{ apc_iterator_create */ ++static zend_object_value apc_iterator_create(zend_class_entry *ce TSRMLS_DC) { ++ zend_object_value retval; ++ apc_iterator_t *iterator; ++ ++ iterator = emalloc(sizeof(apc_iterator_t)); ++ iterator->obj.ce = ce; ++ ALLOC_HASHTABLE(iterator->obj.properties); ++ zend_hash_init(iterator->obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0); ++#ifdef ZEND_ENGINE_2_4 ++ iterator->obj.properties_table = NULL; ++#endif ++ iterator->obj.guards = NULL; ++ iterator->initialized = 0; ++ retval.handle = zend_objects_store_put(iterator, apc_iterator_destroy, apc_iterator_free, NULL TSRMLS_CC); ++ retval.handlers = &apc_iterator_object_handlers; ++ ++ return retval; ++} ++/* }}} */ + ++/* {{{ apc_iterator_search_match ++ * Verify if the key matches oru search parameters + */ ++static int apc_iterator_search_match(apc_iterator_t *iterator, slot_t **slot) { ++ char *key; ++ int key_len; ++ char *fname_key = NULL; ++ int fname_key_len = 0; ++ int rval = 1; ++ ++ if ((*slot)->key.type == APC_CACHE_KEY_FILE) { ++ key = (*slot)->value->data.file.filename; ++ key_len = strlen(key); ++ fname_key_len = spprintf(&fname_key, 0, "%ld %ld", (*slot)->key.data.file.device, (*slot)->key.data.file.inode); ++ } else if ((*slot)->key.type == APC_CACHE_KEY_USER) { ++ key = (char*)(*slot)->key.data.user.identifier; ++ key_len = (*slot)->key.data.user.identifier_len; ++ } else if ((*slot)->key.type == APC_CACHE_KEY_FPFILE) { ++ key = (char*)(*slot)->key.data.fpfile.fullpath; ++ key_len = (*slot)->key.data.fpfile.fullpath_len; ++ } else { ++ return 0; ++ } + -+$VERSION='$Id: apc.php,v 3.65 2006/10/27 18:32:52 shire Exp $'; ++#ifdef ITERATOR_PCRE ++ if (iterator->regex) { ++ rval = (pcre_exec(iterator->re, NULL, key, strlen(key), 0, 0, NULL, 0) >= 0); ++ } ++#endif ++ ++ if (iterator->search_hash) { ++ rval = zend_hash_exists(iterator->search_hash, key, key_len); ++ if (!rval && fname_key) { ++ rval = zend_hash_exists(iterator->search_hash, fname_key, fname_key_len+1); ++ } ++ } + -+////////// READ OPTIONAL CONFIGURATION FILE //////////// -+if (file_exists("apc.conf.php")) include("apc.conf.php"); -+//////////////////////////////////////////////////////// ++ return rval; ++} ++/* }}} */ + -+////////// BEGIN OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////// ++/* {{{ apc_iterator_check_expiry */ ++static int apc_iterator_check_expiry(apc_cache_t* cache, slot_t **slot, time_t t) ++{ ++ if((*slot)->value->type == APC_CACHE_ENTRY_USER) { ++ if((*slot)->value->data.user.ttl) { ++ if((time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) { ++ return 0; ++ } ++ } else if(cache->ttl) { ++ if((*slot)->creation_time + cache->ttl < t) { ++ return 0; ++ } ++ } ++ } else if((*slot)->access_time < (t - cache->ttl)) { ++ return 0; ++ } + -+defaults('USE_AUTHENTICATION',1); // Use (internal) authentication - best choice if -+ // no other authentication is available -+ // If set to 0: -+ // There will be no further authentication. You -+ // will have to handle this by yourself! -+ // If set to 1: -+ // You need to change ADMIN_PASSWORD to make -+ // this work! -+defaults('ADMIN_USERNAME','apc'); // Admin Username -+defaults('ADMIN_PASSWORD','password'); // Admin Password - CHANGE THIS TO ENABLE!!! ++ return 1; ++} ++/* }}} */ + -+// (beckerr) I'm using a clear text password here, because I've no good idea how to let -+// users generate a md5 or crypt password in a easy way to fill it in above ++/* {{{ apc_iterator_fetch_active */ ++static int apc_iterator_fetch_active(apc_iterator_t *iterator TSRMLS_DC) { ++ int count=0; ++ slot_t **slot; ++ apc_iterator_item_t *item; ++ time_t t; + -+//defaults('DATE_FORMAT', "d.m.Y H:i:s"); // German -+defaults('DATE_FORMAT', 'Y/m/d H:i:s'); // US ++ t = apc_time(); + -+defaults('GRAPH_SIZE',200); // Image size ++ while (apc_stack_size(iterator->stack) > 0) { ++ apc_iterator_item_dtor(apc_stack_pop(iterator->stack)); ++ } + -+////////// END OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////// ++ CACHE_LOCK(iterator->cache); ++ while(count <= iterator->chunk_size && iterator->slot_idx < iterator->cache->num_slots) { ++ slot = &iterator->cache->slots[iterator->slot_idx]; ++ while(*slot) { ++ if (apc_iterator_check_expiry(iterator->cache, slot, t)) { ++ if (apc_iterator_search_match(iterator, slot)) { ++ count++; ++ item = apc_iterator_item_ctor(iterator, slot TSRMLS_CC); ++ if (item) { ++ apc_stack_push(iterator->stack, item TSRMLS_CC); ++ } ++ } ++ } ++ slot = &(*slot)->next; ++ } ++ iterator->slot_idx++; ++ } ++ CACHE_UNLOCK(iterator->cache); ++ iterator->stack_idx = 0; ++ return count; ++} ++/* }}} */ + ++/* {{{ apc_iterator_fetch_deleted */ ++static int apc_iterator_fetch_deleted(apc_iterator_t *iterator TSRMLS_DC) { ++ int count=0; ++ slot_t **slot; ++ apc_iterator_item_t *item; + -+// "define if not defined" -+function defaults($d,$v) { -+ if (!defined($d)) define($d,$v); // or just @define(...) ++ CACHE_LOCK(iterator->cache); ++ slot = &iterator->cache->header->deleted_list; ++ while ((*slot) && count <= iterator->slot_idx) { ++ count++; ++ slot = &(*slot)->next; ++ } ++ count = 0; ++ while ((*slot) && count < iterator->chunk_size) { ++ if (apc_iterator_search_match(iterator, slot)) { ++ count++; ++ item = apc_iterator_item_ctor(iterator, slot TSRMLS_CC); ++ if (item) { ++ apc_stack_push(iterator->stack, item TSRMLS_CC); ++ } ++ } ++ slot = &(*slot)->next; ++ } ++ CACHE_UNLOCK(iterator->cache); ++ iterator->slot_idx += count; ++ iterator->stack_idx = 0; ++ return count; +} ++/* }}} */ + -+// rewrite $PHP_SELF to block XSS attacks -+// -+$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : ''; -+$time = time(); -+$host = getenv('HOSTNAME'); -+if($host) { $host = '('.$host.')'; } ++/* {{{ apc_iterator_totals */ ++static void apc_iterator_totals(apc_iterator_t *iterator TSRMLS_DC) { ++ slot_t **slot; ++ int i; + -+// operation constants -+define('OB_HOST_STATS',1); -+define('OB_SYS_CACHE',2); -+define('OB_USER_CACHE',3); -+define('OB_SYS_CACHE_DIR',4); -+define('OB_VERSION_CHECK',9); ++ CACHE_LOCK(iterator->cache); ++ for (i=0; i < iterator->cache->num_slots; i++) { ++ slot = &iterator->cache->slots[i]; ++ while((*slot)) { ++ if (apc_iterator_search_match(iterator, slot)) { ++ iterator->size += (*slot)->value->mem_size; ++ iterator->hits += (*slot)->num_hits; ++ iterator->count++; ++ } ++ slot = &(*slot)->next; ++ } ++ } ++ CACHE_UNLOCK(iterator->cache); ++ iterator->totals_flag = 1; ++} ++/* }}} */ + -+// check validity of input variables -+$vardom=array( -+ 'OB' => '/^\d+$/', // operational mode switch -+ 'CC' => '/^[01]$/', // clear cache requested -+ 'SH' => '/^[a-z0-9]+$/', // shared object description ++/* {{{ proto object APCIterator::__costruct(string cache [, mixed search [, long format [, long chunk_size [, long list ]]]]) */ ++PHP_METHOD(apc_iterator, __construct) { ++ zval *object = getThis(); ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(object TSRMLS_CC); ++ char *cachetype; ++ int cachetype_len; ++ long format = APC_ITER_ALL; ++ long chunk_size=0; ++ zval *search = NULL; ++ long list = APC_LIST_ACTIVE; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zlll", &cachetype, &cachetype_len, &search, &format, &chunk_size, &list) == FAILURE) { ++ return; ++ } + -+ 'IMG' => '/^[123]$/', // image to generate -+ 'LO' => '/^1$/', // login requested ++ if (!APCG(enabled)) { ++ apc_error("APC must be enabled to use APCIterator." TSRMLS_CC); ++ } + -+ 'COUNT' => '/^\d+$/', // number of line displayed in list -+ 'SCOPE' => '/^[AD]$/', // list view scope -+ 'SORT1' => '/^[AHSMCDTZ]$/', // first sort key -+ 'SORT2' => '/^[DA]$/', // second sort key -+ 'AGGR' => '/^\d+$/', // aggregation by dir level -+ 'SEARCH' => '/^.*$/' // aggregation by dir level -+); ++ if (chunk_size < 0) { ++ apc_error("APCIterator chunk size must be 0 or greater." TSRMLS_CC); ++ return; ++ } + -+// default cache mode -+$cache_mode='opcode'; ++ if (format > APC_ITER_ALL) { ++ apc_error("APCIterator format is invalid." TSRMLS_CC); ++ return; ++ } + -+// cache scope -+$scope_list=array( -+ 'A' => 'cache_list', -+ 'D' => 'deleted_list' -+); ++ if (list == APC_LIST_ACTIVE) { ++ iterator->fetch = apc_iterator_fetch_active; ++ } else if (list == APC_LIST_DELETED) { ++ iterator->fetch = apc_iterator_fetch_deleted; ++ } else { ++ apc_warning("APCIterator invalid list type." TSRMLS_CC); ++ return; ++ } + -+// handle POST and GET requests -+if (empty($_REQUEST)) { -+ if (!empty($_GET) && !empty($_POST)) { -+ $_REQUEST = array_merge($_GET, $_POST); -+ } else if (!empty($_GET)) { -+ $_REQUEST = $_GET; -+ } else if (!empty($_POST)) { -+ $_REQUEST = $_POST; -+ } else { -+ $_REQUEST = array(); -+ } ++ if(!strcasecmp(cachetype,"user")) { ++ iterator->cache = apc_user_cache; ++ } else { ++ iterator->cache = apc_cache; ++ } ++ ++ iterator->slot_idx = 0; ++ iterator->stack_idx = 0; ++ iterator->key_idx = 0; ++ iterator->chunk_size = chunk_size == 0 ? APC_DEFAULT_CHUNK_SIZE : chunk_size; ++ iterator->stack = apc_stack_create(chunk_size TSRMLS_CC); ++ iterator->format = format; ++ iterator->totals_flag = 0; ++ iterator->count = 0; ++ iterator->size = 0; ++ iterator->hits = 0; ++ iterator->regex = NULL; ++ iterator->regex_len = 0; ++ iterator->search_hash = NULL; ++ if (search && Z_TYPE_P(search) == IS_STRING && Z_STRLEN_P(search)) { ++#ifdef ITERATOR_PCRE ++ iterator->regex = estrndup(Z_STRVAL_P(search), Z_STRLEN_P(search)); ++ iterator->regex_len = Z_STRLEN_P(search); ++ iterator->re = pcre_get_compiled_regex(Z_STRVAL_P(search), NULL, NULL TSRMLS_CC); ++ ++ if(!iterator->re) { ++ apc_error("Could not compile regular expression: %s" TSRMLS_CC, Z_STRVAL_P(search)); ++ } ++#else ++ apc_error("Regular expressions support is not enabled, please enable PCRE for APCIterator regex support" TSRMLS_CC); ++#endif ++ } else if (search && Z_TYPE_P(search) == IS_ARRAY) { ++ Z_ADDREF_P(search); ++ iterator->search_hash = apc_flip_hash(Z_ARRVAL_P(search)); ++ } ++ iterator->initialized = 1; +} ++/* }}} */ + -+// check parameter syntax -+foreach($vardom as $var => $dom) { -+ if (!isset($_REQUEST[$var])) { -+ $MYREQUEST[$var]=NULL; -+ } else if (!is_array($_REQUEST[$var]) && preg_match($dom,$_REQUEST[$var])) { -+ $MYREQUEST[$var]=$_REQUEST[$var]; -+ } else { -+ $MYREQUEST[$var]=$_REQUEST[$var]=NULL; -+ } ++/* {{{ proto APCIterator::rewind() */ ++PHP_METHOD(apc_iterator, rewind) { ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); ++ ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } ++ ++ if (iterator->initialized == 0) { ++ RETURN_FALSE; ++ } ++ ++ iterator->slot_idx = 0; ++ iterator->stack_idx = 0; ++ iterator->key_idx = 0; ++ iterator->fetch(iterator TSRMLS_CC); +} ++/* }}} */ + -+// check parameter sematics -+if (empty($MYREQUEST['SCOPE'])) $MYREQUEST['SCOPE']="A"; -+if (empty($MYREQUEST['SORT1'])) $MYREQUEST['SORT1']="H"; -+if (empty($MYREQUEST['SORT2'])) $MYREQUEST['SORT2']="D"; -+if (empty($MYREQUEST['OB'])) $MYREQUEST['OB']=OB_HOST_STATS; -+if (!isset($MYREQUEST['COUNT'])) $MYREQUEST['COUNT']=20; -+if (!isset($scope_list[$MYREQUEST['SCOPE']])) $MYREQUEST['SCOPE']='A'; ++/* {{{ proto boolean APCIterator::valid() */ ++PHP_METHOD(apc_iterator, valid) { ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + -+$MY_SELF= -+ "$PHP_SELF". -+ "?SCOPE=".$MYREQUEST['SCOPE']. -+ "&SORT1=".$MYREQUEST['SORT1']. -+ "&SORT2=".$MYREQUEST['SORT2']. -+ "&COUNT=".$MYREQUEST['COUNT']; -+$MY_SELF_WO_SORT= -+ "$PHP_SELF". -+ "?SCOPE=".$MYREQUEST['SCOPE']. -+ "&COUNT=".$MYREQUEST['COUNT']; ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } + -+// authentication needed? -+// -+if (!USE_AUTHENTICATION) { -+ $AUTHENTICATED=1; -+} else { -+ $AUTHENTICATED=0; -+ if (ADMIN_PASSWORD!='password' && ($MYREQUEST['LO'] == 1 || isset($_SERVER['PHP_AUTH_USER']))) { ++ if (iterator->initialized == 0) { ++ RETURN_FALSE; ++ } + -+ if (!isset($_SERVER['PHP_AUTH_USER']) || -+ !isset($_SERVER['PHP_AUTH_PW']) || -+ $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME || -+ $_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) { -+ Header("WWW-Authenticate: Basic realm=\"APC Login\""); -+ Header("HTTP/1.0 401 Unauthorized"); ++ if (apc_stack_size(iterator->stack) == iterator->stack_idx) { ++ iterator->fetch(iterator TSRMLS_CC); ++ } + -+ echo << -+

Rejected!

-+ Wrong Username or Password!
 
  -+ Continue... -+ -+EOB; -+ exit; -+ -+ } else { -+ $AUTHENTICATED=1; -+ } -+ } -+} -+ -+// select cache mode -+if ($AUTHENTICATED && $MYREQUEST['OB'] == OB_USER_CACHE) { -+ $cache_mode='user'; -+} -+// clear cache -+if ($AUTHENTICATED && isset($MYREQUEST['CC']) && $MYREQUEST['CC']) { -+ apc_clear_cache($cache_mode); ++ RETURN_BOOL(apc_stack_size(iterator->stack) == 0 ? 0 : 1); +} ++/* }}} */ + -+if(!function_exists('apc_cache_info') || !($cache=@apc_cache_info($cache_mode))) { -+ echo "No cache info available. APC does not appear to be running."; -+ exit; -+} ++/* {{{ proto mixed APCIterator::current() */ ++PHP_METHOD(apc_iterator, current) { ++ apc_iterator_item_t *item; ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + -+$cache_user = apc_cache_info('user', 1); -+$mem=apc_sma_info(); -+if(!$cache['num_hits']) { $cache['num_hits']=1; $time++; } // Avoid division by 0 errors on a cache clear ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } + -+// don't cache this page -+// -+header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 -+header("Cache-Control: post-check=0, pre-check=0", false); -+header("Pragma: no-cache"); // HTTP/1.0 ++ if (iterator->initialized == 0) { ++ RETURN_FALSE; ++ } + -+function duration($ts) { -+ global $time; -+ $years = (int)((($time - $ts)/(7*86400))/52.177457); -+ $rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400)); -+ $weeks = (int)(($rem)/(7*86400)); -+ $days = (int)(($rem)/86400) - $weeks*7; -+ $hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24; -+ $mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60; -+ $str = ''; -+ if($years==1) $str .= "$years year, "; -+ if($years>1) $str .= "$years years, "; -+ if($weeks==1) $str .= "$weeks week, "; -+ if($weeks>1) $str .= "$weeks weeks, "; -+ if($days==1) $str .= "$days day,"; -+ if($days>1) $str .= "$days days,"; -+ if($hours == 1) $str .= " $hours hour and"; -+ if($hours>1) $str .= " $hours hours and"; -+ if($mins == 1) $str .= " 1 minute"; -+ else $str .= " $mins minutes"; -+ return $str; -+} ++ if (apc_stack_size(iterator->stack) == iterator->stack_idx) { ++ if (iterator->fetch(iterator TSRMLS_CC) == 0) { ++ RETURN_FALSE; ++ } ++ } + -+// create graphics -+// -+function graphics_avail() { -+ return extension_loaded('gd'); ++ item = apc_stack_get(iterator->stack, iterator->stack_idx); ++ RETURN_ZVAL(item->value, 1, 0); +} -+if (isset($MYREQUEST['IMG'])) -+{ -+ if (!graphics_avail()) { -+ exit(0); -+ } ++/* }}} */ + -+ function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) { -+ $r=$diameter/2; -+ $w=deg2rad((360+$start+($end-$start)/2)%360); ++/* {{{ proto string APCIterator::key() */ ++PHP_METHOD(apc_iterator, key) { ++ apc_iterator_item_t *item; ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + -+ -+ if (function_exists("imagefilledarc")) { -+ // exists only if GD 2.0.1 is avaliable -+ imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE); -+ imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE); -+ imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); -+ } else { -+ imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2); -+ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); -+ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); -+ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); -+ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); -+ imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2); -+ } -+ if ($text) { -+ if ($placeindex>0) { -+ imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); -+ imagestring($im,4,$diameter, $placeindex*12,$text,$color1); -+ -+ } else { -+ imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); -+ } -+ } -+ } ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } + -+ function text_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$text,$placeindex=0) { -+ $r=$diameter/2; -+ $w=deg2rad((360+$start+($end-$start)/2)%360); ++ if (iterator->initialized == 0 || apc_stack_size(iterator->stack) == 0) { ++ RETURN_FALSE; ++ } + -+ if ($placeindex>0) { -+ imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); -+ imagestring($im,4,$diameter, $placeindex*12,$text,$color1); -+ -+ } else { -+ imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); -+ } -+ } -+ -+ function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') { -+ global $col_black; -+ $x1=$x+$w-1; -+ $y1=$y+$h-1; ++ if (apc_stack_size(iterator->stack) == iterator->stack_idx) { ++ if (iterator->fetch(iterator TSRMLS_CC) == 0) { ++ RETURN_FALSE; ++ } ++ } + -+ imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black); -+ if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2); -+ else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2); -+ imagerectangle($im, $x, $y1, $x1, $y, $color1); -+ if ($text) { -+ if ($placeindex>0) { -+ -+ if ($placeindex<16) -+ { -+ $px=5; -+ $py=$placeindex*12+6; -+ imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2); -+ imageline($im,$x,$y+$h/2,$px+90,$py,$color2); -+ imagestring($im,2,$px,$py-6,$text,$color1); -+ -+ } else { -+ if ($placeindex<31) { -+ $px=$x+40*2; -+ $py=($placeindex-15)*12+6; -+ } else { -+ $px=$x+40*2+100*intval(($placeindex-15)/15); -+ $py=($placeindex%15)*12+6; -+ } -+ imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2); -+ imageline($im,$x+$w,$y+$h/2,$px,$py,$color2); -+ imagestring($im,2,$px+2,$py-6,$text,$color1); -+ } -+ } else { -+ imagestring($im,4,$x+5,$y1-16,$text,$color1); -+ } -+ } -+ } ++ item = apc_stack_get(iterator->stack, iterator->stack_idx); + ++ if (item->key) { ++ RETURN_STRINGL(item->key, (item->key_len-1), 1); ++ } else { ++ RETURN_LONG(iterator->key_idx); ++ } ++} ++/* }}} */ + -+ $size = GRAPH_SIZE; // image size -+ if ($MYREQUEST['IMG']==3) -+ $image = imagecreate(2*$size+150, $size+10); -+ else -+ $image = imagecreate($size+50, $size+10); ++/* {{{ proto APCIterator::next() */ ++PHP_METHOD(apc_iterator, next) { ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + -+ $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF); -+ $col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30); -+ $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60); -+ $col_black = imagecolorallocate($image, 0, 0, 0); -+ imagecolortransparent($image,$col_white); ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } + -+ switch ($MYREQUEST['IMG']) { -+ -+ case 1: -+ $s=$mem['num_seg']*$mem['seg_size']; -+ $a=$mem['avail_mem']; -+ $x=$y=$size/2; -+ $fuzz = 0.000001; ++ if (iterator->initialized == 0 || apc_stack_size(iterator->stack) == 0) { ++ RETURN_FALSE; ++ } + -+ // This block of code creates the pie chart. It is a lot more complex than you -+ // would expect because we try to visualize any memory fragmentation as well. -+ $angle_from = 0; -+ $string_placement=array(); -+ for($i=0; $i<$mem['num_seg']; $i++) { -+ $ptr = 0; -+ $free = $mem['block_lists'][$i]; -+ foreach($free as $block) { -+ if($block['offset']!=$ptr) { // Used block -+ $angle_to = $angle_from+($block['offset']-$ptr)/$s; -+ if(($angle_to+$fuzz)>1) $angle_to = 1; -+ fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); -+ if (($angle_to-$angle_from)>0.05) { -+ array_push($string_placement, array($angle_from,$angle_to)); -+ } -+ $angle_from = $angle_to; -+ } -+ $angle_to = $angle_from+($block['size'])/$s; -+ if(($angle_to+$fuzz)>1) $angle_to = 1; -+ fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_green); -+ if (($angle_to-$angle_from)>0.05) { -+ array_push($string_placement, array($angle_from,$angle_to)); -+ } -+ $angle_from = $angle_to; -+ $ptr = $block['offset']+$block['size']; -+ } -+ if ($ptr < $mem['seg_size']) { // memory at the end -+ $angle_to = $angle_from + ($mem['seg_size'] - $ptr)/$s; -+ if(($angle_to+$fuzz)>1) $angle_to = 1; -+ fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); -+ if (($angle_to-$angle_from)>0.05) { -+ array_push($string_placement, array($angle_from,$angle_to)); -+ } -+ } -+ } -+ foreach ($string_placement as $angle) { -+ text_arc($image,$x,$y,$size,$angle[0]*360,$angle[1]*360,$col_black,bsize($s*($angle[1]-$angle[0]))); -+ } -+ break; -+ -+ case 2: -+ $s=$cache['num_hits']+$cache['num_misses']; -+ $a=$cache['num_hits']; -+ -+ fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s)); -+ fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s)); -+ break; -+ -+ case 3: -+ $s=$mem['num_seg']*$mem['seg_size']; -+ $a=$mem['avail_mem']; -+ $x=130; -+ $y=1; -+ $j=1; ++ iterator->stack_idx++; ++ iterator->key_idx++; + -+ // This block of code creates the bar chart. It is a lot more complex than you -+ // would expect because we try to visualize any memory fragmentation as well. -+ for($i=0; $i<$mem['num_seg']; $i++) { -+ $ptr = 0; -+ $free = $mem['block_lists'][$i]; -+ foreach($free as $block) { -+ if($block['offset']!=$ptr) { // Used block -+ $h=(GRAPH_SIZE-5)*($block['offset']-$ptr)/$s; -+ if ($h>0) { -+ $j++; -+ if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($block['offset']-$ptr),$j); -+ else fill_box($image,$x,$y,50,$h,$col_black,$col_red); -+ } -+ $y+=$h; -+ } -+ $h=(GRAPH_SIZE-5)*($block['size'])/$s; -+ if ($h>0) { -+ $j++; -+ if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_green,bsize($block['size']),$j); -+ else fill_box($image,$x,$y,50,$h,$col_black,$col_green); -+ } -+ $y+=$h; -+ $ptr = $block['offset']+$block['size']; -+ } -+ if ($ptr < $mem['seg_size']) { // memory at the end -+ $h = (GRAPH_SIZE-5) * ($mem['seg_size'] - $ptr) / $s; -+ if ($h > 0) { -+ fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($mem['seg_size']-$ptr),$j++); -+ } -+ } -+ } -+ break; -+ case 4: -+ $s=$cache['num_hits']+$cache['num_misses']; -+ $a=$cache['num_hits']; -+ -+ fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s)); -+ fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s)); -+ break; -+ -+ } -+ header("Content-type: image/png"); -+ imagepng($image); -+ exit; ++ RETURN_TRUE; +} ++/* }}} */ + -+// pretty printer for byte values -+// -+function bsize($s) { -+ foreach (array('','K','M','G') as $i => $k) { -+ if ($s < 1024) break; -+ $s/=1024; -+ } -+ return sprintf("%5.1f %sBytes",$s,$k); -+} ++/* {{{ proto long APCIterator::getTotalHits() */ ++PHP_METHOD(apc_iterator, getTotalHits) { ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); + -+// sortable table header in "scripts for this host" view -+function sortheader($key,$name,$extra='') { -+ global $MYREQUEST, $MY_SELF_WO_SORT; -+ -+ if ($MYREQUEST['SORT1']==$key) { -+ $MYREQUEST['SORT2'] = $MYREQUEST['SORT2']=='A' ? 'D' : 'A'; -+ } -+ return "$name"; ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } ++ ++ if (iterator->initialized == 0) { ++ RETURN_FALSE; ++ } ++ ++ if (iterator->totals_flag == 0) { ++ apc_iterator_totals(iterator TSRMLS_CC); ++ } + ++ RETURN_LONG(iterator->hits); +} ++/* }}} */ + -+// create menu entry -+function menu_entry($ob,$title) { -+ global $MYREQUEST,$MY_SELF; -+ if ($MYREQUEST['OB']!=$ob) { -+ return "
  • $title
  • "; -+ } else if (empty($MYREQUEST['SH'])) { -+ return "
  • $title
  • "; -+ } else { -+ return "
  • $title
  • "; -+ } ++/* {{{ proto long APCIterator::getTotalSize() */ ++PHP_METHOD(apc_iterator, getTotalSize) { ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); ++ ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } ++ ++ if (iterator->initialized == 0) { ++ RETURN_FALSE; ++ } ++ ++ if (iterator->totals_flag == 0) { ++ apc_iterator_totals(iterator TSRMLS_CC); ++ } ++ ++ RETURN_LONG(iterator->size); +} ++/* }}} */ + -+function put_login_link($s="Login") -+{ -+ global $MY_SELF,$MYREQUEST,$AUTHENTICATED; -+ // needs ADMIN_PASSWORD to be changed! -+ // -+ if (!USE_AUTHENTICATION) { -+ return; -+ } else if (ADMIN_PASSWORD=='password') -+ { -+ print <<$s -+EOB; -+ } else if ($AUTHENTICATED) { -+ print <<$s -+EOB; -+ } ++/* {{{ proto long APCIterator::getTotalCount() */ ++PHP_METHOD(apc_iterator, getTotalCount) { ++ apc_iterator_t *iterator = (apc_iterator_t*)zend_object_store_get_object(getThis() TSRMLS_CC); ++ ++ if (zend_parse_parameters_none() == FAILURE) { ++ return; ++ } ++ ++ if (iterator->initialized == 0) { ++ RETURN_FALSE; ++ } ++ ++ if (iterator->totals_flag == 0) { ++ apc_iterator_totals(iterator TSRMLS_CC); ++ } ++ ++ RETURN_LONG(iterator->count); +} ++/* }}} */ + ++/* {{{ arginfo */ ++#if (PHP_MAJOR_VERSION >= 6 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3)) ++# define PHP_APC_ARGINFO ++#else ++# define PHP_APC_ARGINFO static ++#endif + -+?> -+ -+ -+APC INFO <?php echo $host ?> -+ -+ -+ -+
    -+

    -+ -+
    Opcode Cache
    -+

    -+ -+
    -+
    -+600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim<600: expandtab sw=4 ts=4 sts=4 ++ */ +diff -Naur a/ext/apc/apc_iterator.h b/ext/apc/apc_iterator.h +--- a/ext/apc/apc_iterator.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_iterator.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,117 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Brian Shire | ++ +----------------------------------------------------------------------+ + -+// Display main Menu -+echo << -+
  • Refresh Data
  • -+EOB; -+echo -+ menu_entry(1,'View Host Stats'), -+ menu_entry(2,'System Cache Entries'); -+if ($AUTHENTICATED) { -+ echo menu_entry(4,'Per-Directory Entries'); -+} -+echo -+ menu_entry(3,'User Cache Entries'), -+ menu_entry(9,'Version Check'); -+ -+if ($AUTHENTICATED) { -+ echo <<Clear $cache_mode Cache -+EOB; -+} -+echo << -+EOB; ++ */ + ++/* $Id: apc_iterator.h 307048 2011-01-03 23:53:17Z kalle $ */ + -+// CONTENT -+echo << -+EOB; ++#ifndef APC_ITERATOR_H ++#define APC_ITERATOR_H + -+// MAIN SWITCH STATEMENT ++#include "apc.h" ++#include "apc_stack.h" + -+switch ($MYREQUEST['OB']) { ++#if HAVE_PCRE || HAVE_BUNDLED_PCRE ++/* Deal with problem present until php-5.2.2 where php_pcre.h was not installed correctly */ ++# if !HAVE_BUNDLED_PCRE && PHP_MAJOR_VERSION == 5 && (PHP_MINOR_VERSION < 2 || (PHP_MINOR_VERSION == 2 && PHP_RELEASE_VERSION < 2)) ++# include "apc_php_pcre.h" ++# else ++# include "ext/pcre/php_pcre.h" ++# endif ++# include "ext/standard/php_smart_str.h" ++# define ITERATOR_PCRE 1 ++#endif + + ++#define APC_ITERATOR_NAME "APCIterator" ++ ++#define APC_DEFAULT_CHUNK_SIZE 100 ++ ++#define APC_LIST_ACTIVE 0x1 ++#define APC_LIST_DELETED 0x2 ++ ++#define APC_ITER_TYPE (1L << 0) ++#define APC_ITER_KEY (1L << 1) ++#define APC_ITER_FILENAME (1L << 2) ++#define APC_ITER_DEVICE (1L << 3) ++#define APC_ITER_INODE (1L << 4) ++#define APC_ITER_VALUE (1L << 5) ++#define APC_ITER_MD5 (1L << 6) ++#define APC_ITER_NUM_HITS (1L << 7) ++#define APC_ITER_MTIME (1L << 8) ++#define APC_ITER_CTIME (1L << 9) ++#define APC_ITER_DTIME (1L << 10) ++#define APC_ITER_ATIME (1L << 11) ++#define APC_ITER_REFCOUNT (1L << 12) ++#define APC_ITER_MEM_SIZE (1L << 13) ++#define APC_ITER_TTL (1L << 14) ++ ++#define APC_ITER_NONE (0x00000000L) ++#define APC_ITER_ALL (0xffffffffL) ++ ++typedef void* (*apc_iterator_item_cb_t)(slot_t **slot); ++ ++ ++/* {{{ apc_iterator_t */ ++typedef struct _apc_iterator_t { ++ zend_object obj; /* must always be first */ ++ short int initialized; /* sanity check in case __construct failed */ ++ long format; /* format bitmask of the return values ie: key, value, info */ ++ int (*fetch)(struct _apc_iterator_t *iterator TSRMLS_DC); ++ /* fetch callback to fetch items from cache slots or lists */ ++ apc_cache_t *cache; /* cache which we are iterating on */ ++ long slot_idx; /* index to the slot array or linked list */ ++ long chunk_size; /* number of entries to pull down per fetch */ ++ apc_stack_t *stack; /* stack of entries pulled from cache */ ++ int stack_idx; /* index into the current stack */ ++#ifdef ITERATOR_PCRE ++ pcre *re; /* regex filter on entry identifiers */ ++#endif ++ char *regex; /* original regex expression or NULL */ ++ int regex_len; /* regex length */ ++ HashTable *search_hash; /* hash of keys to iterate over */ ++ long key_idx; /* incrementing index for numerical keys */ ++ short int totals_flag; /* flag if totals have been calculated */ ++ long hits; /* hit total */ ++ size_t size; /* size total */ ++ long count; /* count total */ ++} apc_iterator_t; ++/* }}} */ + ++/* {{{ apc_iterator_item */ ++typedef struct _apc_iterator_item_t { ++ char *key; /* string key */ ++ long key_len; /* strlen of key */ ++ char *filename_key; /* filename key used for deletion */ ++ zval *value; ++} apc_iterator_item_t; ++/* }}} */ + + -+// ----------------------------------------------- -+// Host Stats -+// ----------------------------------------------- -+case OB_HOST_STATS: -+ $mem_size = $mem['num_seg']*$mem['seg_size']; -+ $mem_avail= $mem['avail_mem']; -+ $mem_used = $mem_size-$mem_avail; -+ $seg_size = bsize($mem['seg_size']); -+ $req_rate = sprintf("%.2f",($cache['num_hits']+$cache['num_misses'])/($time-$cache['start_time'])); -+ $hit_rate = sprintf("%.2f",($cache['num_hits'])/($time-$cache['start_time'])); -+ $miss_rate = sprintf("%.2f",($cache['num_misses'])/($time-$cache['start_time'])); -+ $insert_rate = sprintf("%.2f",($cache['num_inserts'])/($time-$cache['start_time'])); -+ $req_rate_user = sprintf("%.2f",($cache_user['num_hits']+$cache_user['num_misses'])/($time-$cache_user['start_time'])); -+ $hit_rate_user = sprintf("%.2f",($cache_user['num_hits'])/($time-$cache_user['start_time'])); -+ $miss_rate_user = sprintf("%.2f",($cache_user['num_misses'])/($time-$cache_user['start_time'])); -+ $insert_rate_user = sprintf("%.2f",($cache_user['num_inserts'])/($time-$cache_user['start_time'])); -+ $apcversion = phpversion('apc'); -+ $phpversion = phpversion(); -+ $number_files = $cache['num_entries']; -+ $size_files = bsize($cache['mem_size']); -+ $number_vars = $cache_user['num_entries']; -+ $size_vars = bsize($cache_user['mem_size']); -+ $i=0; -+ echo <<< EOB -+

    General Cache Information

    -+ -+ -+ -+EOB; ++extern int apc_iterator_init(int module_number TSRMLS_DC); ++extern int apc_iterator_delete(zval *zobj TSRMLS_DC); + -+ if(!empty($_SERVER['SERVER_NAME'])) -+ echo "\n"; -+ if(!empty($_SERVER['SERVER_SOFTWARE'])) -+ echo "\n"; ++#endif + -+ echo << -+EOB; -+ echo ''; -+ echo ''; -+ echo ''; -+ echo <<
    APC Version$apcversion
    PHP Version$phpversion
    APC Host{$_SERVER['SERVER_NAME']} $host
    Server Software{$_SERVER['SERVER_SOFTWARE']}
    Shared Memory{$mem['num_seg']} Segment(s) with $seg_size -+
    ({$cache['memory_type']} memory, {$cache['locking_type']} locking) -+
    Start Time',date(DATE_FORMAT,$cache['start_time']),'
    Uptime',duration($cache['start_time']),'
    File Upload Support',$cache['file_upload_progress'],'
    -+
    ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_lock.h b/ext/apc/apc_lock.h +--- a/ext/apc/apc_lock.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_lock.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,160 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: George Schlossnagle | ++ | Rasmus Lerdorf | ++ | Pierre Joye | ++ +----------------------------------------------------------------------+ + -+

    File Cache Information

    -+ -+ -+ -+ -+ -+ -+ -+ -+ -+
    Cached Files$number_files ($size_files)
    Hits{$cache['num_hits']}
    Misses{$cache['num_misses']}
    Request Rate (hits, misses)$req_rate cache requests/second
    Hit Rate$hit_rate cache requests/second
    Miss Rate$miss_rate cache requests/second
    Insert Rate$insert_rate cache requests/second
    Cache full count{$cache['expunges']}
    -+
    ++ 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. + -+

    User Cache Information

    -+ -+ -+ -+ -+ -+ -+ -+ -+ ++ All other licensing and usage conditions are those of the PHP Group. + -+
    Cached Variables$number_vars ($size_vars)
    Hits{$cache_user['num_hits']}
    Misses{$cache_user['num_misses']}
    Request Rate (hits, misses)$req_rate_user cache requests/second
    Hit Rate$hit_rate_user cache requests/second
    Miss Rate$miss_rate_user cache requests/second
    Insert Rate$insert_rate_user cache requests/second
    Cache full count{$cache_user['expunges']}
    -+
    ++ */ + -+

    Runtime Settings

    -+EOB; ++/* $Id: apc_lock.h 311339 2011-05-22 17:18:49Z gopalv $ */ + -+ $j = 0; -+ foreach (ini_get_all('apc') as $k => $v) { -+ echo "\n"; -+ $j = 1 - $j; -+ } ++#ifndef APC_LOCK ++#define APC_LOCK + -+ if($mem['num_seg']>1 || $mem['num_seg']==1 && count($mem['block_lists'][0])>1) -+ $mem_note = "Memory Usage
    (multiple slices indicate fragments)"; -+ else -+ $mem_note = "Memory Usage"; ++#ifdef HAVE_CONFIG_H ++# include ++#endif + -+ echo <<< EOB -+
    ",$k,"",str_replace(',',',
    ',$v['local_value']),"
    -+
    ++#include "apc.h" ++#include "apc_sem.h" ++#include "apc_fcntl.h" ++#include "apc_pthreadmutex.h" ++#include "apc_pthreadrwlock.h" ++#include "apc_spin.h" ++#include "apc_windows_srwlock_kernel.h" + -+

    Host Status Diagrams

    -+ -+EOB; -+ $size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10); -+ echo << -+ -+ -+ -+EOB; ++/* {{{ generic locking macros */ ++#define CREATE_LOCK(lock) apc_lck_create(NULL, 0, 1, lock) ++#define DESTROY_LOCK(lock) apc_lck_destroy(lock) ++#define LOCK(lock) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(lock); } ++#define RDLOCK(lock) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(lock); } ++#define UNLOCK(lock) { apc_lck_unlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); } ++#define RDUNLOCK(lock) { apc_lck_rdunlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); } ++/* }}} */ + -+ echo -+ graphics_avail() ? -+ ''. -+ "". -+ "\n" -+ : "", -+ '', -+ '\n", -+ '\n", -+ '', -+ '', -+ '\n", -+ '\n"; -+ echo <<< EOB -+ -+
    $mem_noteHits & Misses
    \"\"\"\"
     Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size)," Hits: ',$cache['num_hits'].sprintf(" (%.1f%%)",$cache['num_hits']*100/($cache['num_hits']+$cache['num_misses'])),"
     Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size)," Misses: ',$cache['num_misses'].sprintf(" (%.1f%%)",$cache['num_misses']*100/($cache['num_hits']+$cache['num_misses'])),"
    ++/* atomic operations : rdlocks are impossible without these */ ++#if HAVE_ATOMIC_OPERATIONS ++# ifdef PHP_WIN32 ++# define ATOMIC_INC(a) InterlockedIncrement(&a) ++# define ATOMIC_DEC(a) InterlockedDecrement(&a) ++# else ++# define ATOMIC_INC(a) __sync_add_and_fetch(&a, 1) ++# define ATOMIC_DEC(a) __sync_sub_and_fetch(&a, 1) ++# endif ++#endif + -+
    -+

    Detailed Memory Usage and Fragmentation

    -+ -+ -+ -+ -+EOB; -+ if(isset($mem['adist'])) { -+ foreach($mem['adist'] as $i=>$v) { -+ $cur = pow(2,$i); $nxt = pow(2,$i+1)-1; -+ if($i==0) $range = "1"; -+ else $range = "$cur - $nxt"; -+ echo "\n"; -+ } ++ if (p == NULL) { ++ return; ++ } ++ ++ assert(sma_initialized); ++ ++ ++ for (i = 0; i < sma_numseg; i++) { ++ offset = (size_t)((char *)p - SMA_ADDR(i)); ++ if (p >= (void*)SMA_ADDR(i) && offset < sma_segsize) { ++ LOCK(SMA_LCK(i)); ++ d_size = sma_deallocate(SMA_HDR(i), offset); ++ UNLOCK(SMA_LCK(i)); ++#ifdef VALGRIND_FREELIKE_BLOCK ++ VALGRIND_FREELIKE_BLOCK(p, 0); ++#endif ++ return; + } -+ echo <<

    -+EOB; ++#if defined(APC_SEM_LOCKS) ++# define APC_LOCK_TYPE "IPC Semaphore" ++# define RDLOCK_AVAILABLE 0 ++# define NONBLOCKING_LOCK_AVAILABLE 1 ++# define apc_lck_t int ++# define apc_lck_create(a,b,c,d) d=apc_sem_create((b),(c) TSRMLS_CC) ++# define apc_lck_destroy(a) apc_sem_destroy(a) ++# define apc_lck_lock(a) apc_sem_lock(a TSRMLS_CC) ++# define apc_lck_nb_lock(a) apc_sem_nonblocking_lock(a TSRMLS_CC) ++# define apc_lck_rdlock(a) apc_sem_lock(a TSRMLS_CC) ++# define apc_lck_unlock(a) apc_sem_unlock(a TSRMLS_CC) ++# define apc_lck_rdunlock(a) apc_sem_unlock(a TSRMLS_CC) ++#elif defined(APC_PTHREADMUTEX_LOCKS) ++# define APC_LOCK_TYPE "pthread mutex Locks" ++# define RDLOCK_AVAILABLE 0 ++# define NONBLOCKING_LOCK_AVAILABLE 1 ++# define apc_lck_t pthread_mutex_t ++# define apc_lck_create(a,b,c,d) apc_pthreadmutex_create((pthread_mutex_t*)&d TSRMLS_CC) ++# define apc_lck_destroy(a) apc_pthreadmutex_destroy(&a) ++# define apc_lck_lock(a) apc_pthreadmutex_lock(&a TSRMLS_CC) ++# define apc_lck_nb_lock(a) apc_pthreadmutex_nonblocking_lock(&a TSRMLS_CC) ++# define apc_lck_rdlock(a) apc_pthreadmutex_lock(&a TSRMLS_CC) ++# define apc_lck_unlock(a) apc_pthreadmutex_unlock(&a TSRMLS_CC) ++# define apc_lck_rdunlock(a) apc_pthreadmutex_unlock(&a TSRMLS_CC) ++#elif defined(APC_PTHREADRW_LOCKS) ++# define APC_LOCK_TYPE "pthread read/write Locks" ++# define RDLOCK_AVAILABLE 1 ++# define NONBLOCKING_LOCK_AVAILABLE 1 ++# define apc_lck_t pthread_rwlock_t ++# define apc_lck_create(a,b,c,d) apc_pthreadrwlock_create((pthread_rwlock_t*)&d TSRMLS_CC) ++# define apc_lck_destroy(a) apc_pthreadrwlock_destroy(&a) ++# define apc_lck_lock(a) apc_pthreadrwlock_lock(&a TSRMLS_CC) ++# define apc_lck_nb_lock(a) apc_pthreadrwlock_nonblocking_lock(&a TSRMLS_CC) ++# define apc_lck_rdlock(a) apc_pthreadrwlock_rdlock(&a TSRMLS_CC) ++# define apc_lck_unlock(a) apc_pthreadrwlock_unlock(&a TSRMLS_CC) ++# define apc_lck_rdunlock(a) apc_pthreadrwlock_unlock(&a TSRMLS_CC) ++#elif defined(APC_SPIN_LOCKS) ++# define APC_LOCK_TYPE "spin Locks" ++# define RDLOCK_AVAILABLE 0 ++# define NONBLOCKING_LOCK_AVAILABLE APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE ++# define apc_lck_t slock_t ++# define apc_lck_create(a,b,c,d) apc_slock_create((slock_t*)&(d)) ++# define apc_lck_destroy(a) apc_slock_destroy(&a) ++# define apc_lck_lock(a) apc_slock_lock(&a TSRMLS_CC) ++# define apc_lck_nb_lock(a) apc_slock_nonblocking_lock(&a) ++# define apc_lck_rdlock(a) apc_slock_lock(&a TSRMLS_CC) ++# define apc_lck_unlock(a) apc_slock_unlock(&a) ++# define apc_lck_rdunlock(a) apc_slock_unlock(&a) ++#elif defined(APC_SRWLOCK_NATIVE) && defined(PHP_WIN32) ++# define APC_LOCK_TYPE "Windows Slim RWLOCK (native)" ++# define RDLOCK_AVAILABLE 1 ++# define NONBLOCKING_LOCK_AVAILABLE 0 ++# define apc_lck_t SRWLOCK ++# define apc_lck_create(a,b,c,d) InitializeSRWLock((SRWLOCK*)&(d)) ++# define apc_lck_destroy(a) ++# define apc_lck_lock(a) AcquireSRWLockExclusive(&a) ++# define apc_lck_rdlock(a) AcquireSRWLockShared(&a) ++# define apc_lck_unlock(a) ReleaseSRWLockExclusive(&a) ++# define apc_lck_rdunlock(a) ReleaseSRWLockShared(&a) ++# if NONBLOCKING_LOCK_AVAILABLE==1 /* Only in win7/2008 */ ++# define apc_lck_nb_lock(a) (TryAcquireSRWLockExclusive(&a TSRMLS_CC) == 0 ? 1 : 0); ++# endif ++#elif defined(APC_SRWLOCK_KERNEL) && defined(PHP_WIN32) ++# define APC_LOCK_TYPE "Windows Slim RWLOCK (kernel)" ++# define RDLOCK_AVAILABLE 1 ++# define NONBLOCKING_LOCK_AVAILABLE 0 ++# define apc_lck_t apc_windows_cs_rwlock_t ++# define apc_lck_create(a,b,c,d) apc_windows_cs_create((apc_windows_cs_rwlock_t*)&(d) TSRMLS_CC) ++# define apc_lck_destroy(a) apc_windows_cs_destroy(&a); ++# define apc_lck_lock(a) apc_windows_cs_lock(&a TSRMLS_CC) ++# define apc_lck_rdlock(a) apc_windows_cs_rdlock(&a TSRMLS_CC) ++# define apc_lck_unlock(a) apc_windows_cs_unlock_wr(&a TSRMLS_CC) ++# define apc_lck_rdunlock(a) apc_windows_cs_unlock_rd(&a TSRMLS_CC) ++#else ++# define APC_LOCK_TYPE "File Locks" ++# ifdef HAVE_ATOMIC_OPERATIONS ++# define RDLOCK_AVAILABLE 1 ++# endif ++# ifdef PHP_WIN32 ++# define NONBLOCKING_LOCK_AVAILABLE 0 ++# else ++# define NONBLOCKING_LOCK_AVAILABLE 1 ++# endif ++# define apc_lck_t int ++# define apc_lck_create(a,b,c,d) d=apc_fcntl_create((a) TSRMLS_CC) ++# define apc_lck_destroy(a) apc_fcntl_destroy(a) ++# define apc_lck_lock(a) apc_fcntl_lock(a TSRMLS_CC) ++# define apc_lck_nb_lock(a) apc_fcntl_nonblocking_lock(a TSRMLS_CC) ++# define apc_lck_rdlock(a) apc_fcntl_rdlock(a TSRMLS_CC) ++# define apc_lck_unlock(a) apc_fcntl_unlock(a TSRMLS_CC) ++# define apc_lck_rdunlock(a) apc_fcntl_unlock(a TSRMLS_CC) ++#endif + -+ // Fragementation: (freeseg - 1) / total_seg -+ $nseg = $freeseg = $fragsize = $freetotal = 0; -+ for($i=0; $i<$mem['num_seg']; $i++) { -+ $ptr = 0; -+ foreach($mem['block_lists'][$i] as $block) { -+ if ($block['offset'] != $ptr) { -+ ++$nseg; ++#endif +diff -Naur a/ext/apc/apc_main.c b/ext/apc/apc_main.c +--- a/ext/apc/apc_main.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_main.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,1030 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | Rasmus Lerdorf | ++ | Arun C. Murthy | ++ | Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ ++ ++ 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 324326 2012-03-18 13:19:50Z 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 ++#ifndef ZTS ++ apc_interned_strings_init(TSRMLS_C); ++#endif ++#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); ++ } ++ ++#ifdef ZEND_ENGINE_2_4 ++#ifndef ZTS ++ apc_interned_strings_shutdown(TSRMLS_C); ++#endif ++#endif ++ ++ apc_cache_destroy(apc_cache TSRMLS_CC); ++ apc_cache_destroy(apc_user_cache TSRMLS_CC); ++ apc_sma_cleanup(TSRMLS_C); ++ ++ 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 ++ */ +diff -Naur a/ext/apc/apc_main.h b/ext/apc/apc_main.h +--- a/ext/apc/apc_main.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_main.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,88 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | George Schlossnagle | ++ | Rasmus Lerdorf | ++ | Arun C. Murthy | ++ | Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ ++ ++ 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.h 308594 2011-02-23 12:35:33Z gopalv $ */ ++ ++#ifndef APC_MAIN_H ++#define APC_MAIN_H ++ ++#include "apc_pool.h" ++#include "apc_serializer.h" ++ ++/* ++ * This module provides the primary interface between PHP and APC. ++ */ ++ ++extern int apc_module_init(int module_number TSRMLS_DC); ++extern int apc_module_shutdown(TSRMLS_D); ++extern int apc_process_init(int module_number TSRMLS_DC); ++extern int apc_process_shutdown(TSRMLS_D); ++extern int apc_request_init(TSRMLS_D); ++extern int apc_request_shutdown(TSRMLS_D); ++ ++typedef enum _apc_copy_type { ++ APC_NO_COPY = 0, ++ APC_COPY_IN_OPCODE, ++ APC_COPY_OUT_OPCODE, ++ APC_COPY_IN_USER, ++ APC_COPY_OUT_USER ++} apc_copy_type; ++ ++typedef struct _apc_context_t ++{ ++ apc_pool *pool; ++ apc_copy_type copy; ++ unsigned int force_update:1; ++} apc_context_t; ++ ++/* {{{ struct apc_serializer_t */ ++typedef struct apc_serializer_t apc_serializer_t; ++struct apc_serializer_t { ++ const char *name; ++ apc_serialize_t serialize; ++ apc_unserialize_t unserialize; ++ void *config; ++}; ++/* }}} */ ++ ++apc_serializer_t* apc_get_serializers(TSRMLS_D); ++apc_serializer_t* apc_find_serializer(const char* name TSRMLS_DC); ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_mmap.c b/ext/apc/apc_mmap.c +--- a/ext/apc/apc_mmap.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_mmap.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,177 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Community Connect Inc. in 2002 ++ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. ++ Future revisions and derivatives of this source code must acknowledge ++ Community Connect Inc. as the original contributor of this module by ++ leaving this note intact in the source code. ++ ++ All other licensing and usage conditions are those of the PHP Group. ++ ++ */ ++ ++/* $Id: apc_mmap.c 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#include "apc.h" ++#include "apc_mmap.h" ++#include "apc_lock.h" ++ ++#if APC_MMAP ++ ++#include ++#include ++#include ++ ++/* ++ * Some operating systems (like FreeBSD) have a MAP_NOSYNC flag that ++ * tells whatever update daemons might be running to not flush dirty ++ * vm pages to disk unless absolutely necessary. My guess is that ++ * most systems that don't have this probably default to only synching ++ * to disk when absolutely necessary. ++ */ ++#ifndef MAP_NOSYNC ++#define MAP_NOSYNC 0 ++#endif ++ ++/* support for systems where MAP_ANONYMOUS is defined but not MAP_ANON, ie: HP-UX bug #14615 */ ++#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) ++# define MAP_ANON MAP_ANONYMOUS ++#endif ++ ++apc_segment_t apc_mmap(char *file_mask, size_t size TSRMLS_DC) ++{ ++ apc_segment_t segment; ++ ++ int fd = -1; ++ int flags = MAP_SHARED | MAP_NOSYNC; ++ int remap = 1; ++ ++ /* If no filename was provided, do an anonymous mmap */ ++ if(!file_mask || (file_mask && !strlen(file_mask))) { ++#if !defined(MAP_ANON) ++ apc_error("Anonymous mmap does not apear to be available on this system (MAP_ANON/MAP_ANONYMOUS). Please see the apc.mmap_file_mask INI option." TSRMLS_CC); ++#else ++ fd = -1; ++ flags = MAP_SHARED | MAP_ANON; ++ remap = 0; ++#endif ++ } else if(!strcmp(file_mask,"/dev/zero")) { ++ fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); ++ if(fd == -1) { ++ apc_error("apc_mmap: open on /dev/zero failed:" TSRMLS_CC); ++ goto error; ++ } ++ remap = 0; /* cannot remap */ ++ } else if(strstr(file_mask,".shm")) { ++ /* ++ * If the filemask contains .shm we try to do a POSIX-compliant shared memory ++ * backed mmap which should avoid synchs on some platforms. At least on ++ * FreeBSD this implies MAP_NOSYNC and on Linux it is equivalent of mmap'ing ++ * a file in a mounted shmfs. For this to work on Linux you need to make sure ++ * you actually have shmfs mounted. Also on Linux, make sure the file_mask you ++ * pass in has a leading / and no other /'s. eg. /apc.shm.XXXXXX ++ * On FreeBSD these are mapped onto the regular filesystem so you can put whatever ++ * path you want here. ++ */ ++ if(!mktemp(file_mask)) { ++ apc_error("apc_mmap: mktemp on %s failed:" TSRMLS_CC, file_mask); ++ goto error; ++ } ++ fd = shm_open(file_mask, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); ++ if(fd == -1) { ++ apc_error("apc_mmap: shm_open on %s failed:" TSRMLS_CC, file_mask); ++ goto error; ++ } ++ if (ftruncate(fd, size) < 0) { ++ close(fd); ++ shm_unlink(file_mask); ++ apc_error("apc_mmap: ftruncate failed:" TSRMLS_CC); ++ goto error; ++ } ++ shm_unlink(file_mask); ++ } else { ++ /* ++ * Otherwise we do a normal filesystem mmap ++ */ ++ fd = mkstemp(file_mask); ++ if(fd == -1) { ++ apc_error("apc_mmap: mkstemp on %s failed:" TSRMLS_CC, file_mask); ++ goto error; ++ } ++ if (ftruncate(fd, size) < 0) { ++ close(fd); ++ unlink(file_mask); ++ apc_error("apc_mmap: ftruncate failed:" TSRMLS_CC); ++ goto error; ++ } ++ unlink(file_mask); ++ } ++ ++ segment.shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0); ++ segment.size = size; ++ ++#ifdef APC_MEMPROTECT ++ if(remap) { ++ segment.roaddr = (void *)mmap(NULL, size, PROT_READ, flags, fd, 0); ++ } else { ++ segment.roaddr = NULL; ++ } ++#endif ++ ++ if((long)segment.shmaddr == -1) { ++ apc_error("apc_mmap: mmap failed:" TSRMLS_CC); ++ } ++ ++ if(fd != -1) close(fd); ++ ++ return segment; ++ ++error: ++ ++ segment.shmaddr = (void*)-1; ++ segment.size = 0; ++#ifdef APC_MEMPROTECT ++ segment.roaddr = NULL; ++#endif ++ return segment; ++} ++ ++void apc_unmap(apc_segment_t *segment TSRMLS_DC) ++{ ++ if (munmap(segment->shmaddr, segment->size) < 0) { ++ apc_warning("apc_unmap: munmap failed:" TSRMLS_CC); ++ } ++ ++#ifdef APC_MEMPROTECT ++ if (segment->roaddr && munmap(segment->roaddr, segment->size) < 0) { ++ apc_warning("apc_unmap: munmap failed:" TSRMLS_CC); ++ } ++#endif ++ ++} ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_mmap.h b/ext/apc/apc_mmap.h +--- a/ext/apc/apc_mmap.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_mmap.h 2012-07-20 00:10:35.000000000 +0200 +@@ -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: Gopal V | ++ +----------------------------------------------------------------------+ ++ ++ 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_mmap.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef APC_MMAP_H ++#define APC_MMAP_H ++ ++#include ++ ++#include "apc.h" ++#include "apc_sma.h" ++ ++/* Wrapper functions for shared memory mapped files */ ++ ++#if APC_MMAP ++apc_segment_t apc_mmap(char *file_mask, size_t size TSRMLS_DC); ++void apc_unmap(apc_segment_t* segment TSRMLS_DC); ++#endif ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc.php b/ext/apc/apc.php +--- a/ext/apc/apc.php 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc.php 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,1362 @@ ++ | ++ | Rasmus Lerdorf | ++ | Ilia Alshanetsky | ++ +----------------------------------------------------------------------+ ++ ++ All other licensing and usage conditions are those of the PHP Group. ++ ++ */ ++ ++$VERSION='$Id: apc.php 325483 2012-05-01 00:34:04Z rasmus $'; ++ ++////////// READ OPTIONAL CONFIGURATION FILE //////////// ++if (file_exists("apc.conf.php")) include("apc.conf.php"); ++//////////////////////////////////////////////////////// ++ ++////////// BEGIN OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////// ++ ++defaults('USE_AUTHENTICATION',1); // Use (internal) authentication - best choice if ++ // no other authentication is available ++ // If set to 0: ++ // There will be no further authentication. You ++ // will have to handle this by yourself! ++ // If set to 1: ++ // You need to change ADMIN_PASSWORD to make ++ // this work! ++defaults('ADMIN_USERNAME','apc'); // Admin Username ++defaults('ADMIN_PASSWORD','password'); // Admin Password - CHANGE THIS TO ENABLE!!! ++ ++// (beckerr) I'm using a clear text password here, because I've no good idea how to let ++// users generate a md5 or crypt password in a easy way to fill it in above ++ ++//defaults('DATE_FORMAT', "d.m.Y H:i:s"); // German ++defaults('DATE_FORMAT', 'Y/m/d H:i:s'); // US ++ ++defaults('GRAPH_SIZE',200); // Image size ++ ++//defaults('PROXY', 'tcp://127.0.0.1:8080'); ++ ++////////// END OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////// ++ ++ ++// "define if not defined" ++function defaults($d,$v) { ++ if (!defined($d)) define($d,$v); // or just @define(...) ++} ++ ++// rewrite $PHP_SELF to block XSS attacks ++// ++$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],''), ENT_QUOTES, 'UTF-8') : ''; ++$time = time(); ++$host = php_uname('n'); ++if($host) { $host = '('.$host.')'; } ++if (isset($_SERVER['SERVER_ADDR'])) { ++ $host .= ' ('.$_SERVER['SERVER_ADDR'].')'; ++} ++ ++// operation constants ++define('OB_HOST_STATS',1); ++define('OB_SYS_CACHE',2); ++define('OB_USER_CACHE',3); ++define('OB_SYS_CACHE_DIR',4); ++define('OB_VERSION_CHECK',9); ++ ++// check validity of input variables ++$vardom=array( ++ 'OB' => '/^\d+$/', // operational mode switch ++ 'CC' => '/^[01]$/', // clear cache requested ++ 'DU' => '/^.*$/', // Delete User Key ++ 'SH' => '/^[a-z0-9]+$/', // shared object description ++ ++ 'IMG' => '/^[123]$/', // image to generate ++ 'LO' => '/^1$/', // login requested ++ ++ 'COUNT' => '/^\d+$/', // number of line displayed in list ++ 'SCOPE' => '/^[AD]$/', // list view scope ++ 'SORT1' => '/^[AHSMCDTZ]$/', // first sort key ++ 'SORT2' => '/^[DA]$/', // second sort key ++ 'AGGR' => '/^\d+$/', // aggregation by dir level ++ 'SEARCH' => '~^[a-zA-Z0-9/_.-]*$~' // aggregation by dir level ++); ++ ++// default cache mode ++$cache_mode='opcode'; ++ ++// cache scope ++$scope_list=array( ++ 'A' => 'cache_list', ++ 'D' => 'deleted_list' ++); ++ ++// handle POST and GET requests ++if (empty($_REQUEST)) { ++ if (!empty($_GET) && !empty($_POST)) { ++ $_REQUEST = array_merge($_GET, $_POST); ++ } else if (!empty($_GET)) { ++ $_REQUEST = $_GET; ++ } else if (!empty($_POST)) { ++ $_REQUEST = $_POST; ++ } else { ++ $_REQUEST = array(); ++ } ++} ++ ++// check parameter syntax ++foreach($vardom as $var => $dom) { ++ if (!isset($_REQUEST[$var])) { ++ $MYREQUEST[$var]=NULL; ++ } else if (!is_array($_REQUEST[$var]) && preg_match($dom.'D',$_REQUEST[$var])) { ++ $MYREQUEST[$var]=$_REQUEST[$var]; ++ } else { ++ $MYREQUEST[$var]=$_REQUEST[$var]=NULL; ++ } ++} ++ ++// check parameter sematics ++if (empty($MYREQUEST['SCOPE'])) $MYREQUEST['SCOPE']="A"; ++if (empty($MYREQUEST['SORT1'])) $MYREQUEST['SORT1']="H"; ++if (empty($MYREQUEST['SORT2'])) $MYREQUEST['SORT2']="D"; ++if (empty($MYREQUEST['OB'])) $MYREQUEST['OB']=OB_HOST_STATS; ++if (!isset($MYREQUEST['COUNT'])) $MYREQUEST['COUNT']=20; ++if (!isset($scope_list[$MYREQUEST['SCOPE']])) $MYREQUEST['SCOPE']='A'; ++ ++$MY_SELF= ++ "$PHP_SELF". ++ "?SCOPE=".$MYREQUEST['SCOPE']. ++ "&SORT1=".$MYREQUEST['SORT1']. ++ "&SORT2=".$MYREQUEST['SORT2']. ++ "&COUNT=".$MYREQUEST['COUNT']; ++$MY_SELF_WO_SORT= ++ "$PHP_SELF". ++ "?SCOPE=".$MYREQUEST['SCOPE']. ++ "&COUNT=".$MYREQUEST['COUNT']; ++ ++// authentication needed? ++// ++if (!USE_AUTHENTICATION) { ++ $AUTHENTICATED=1; ++} else { ++ $AUTHENTICATED=0; ++ if (ADMIN_PASSWORD!='password' && ($MYREQUEST['LO'] == 1 || isset($_SERVER['PHP_AUTH_USER']))) { ++ ++ if (!isset($_SERVER['PHP_AUTH_USER']) || ++ !isset($_SERVER['PHP_AUTH_PW']) || ++ $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME || ++ $_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) { ++ Header("WWW-Authenticate: Basic realm=\"APC Login\""); ++ Header("HTTP/1.0 401 Unauthorized"); ++ ++ echo << ++

    Rejected!

    ++ Wrong Username or Password!
     
      ++ Continue... ++ ++EOB; ++ exit; ++ ++ } else { ++ $AUTHENTICATED=1; ++ } ++ } ++} ++ ++// select cache mode ++if ($AUTHENTICATED && $MYREQUEST['OB'] == OB_USER_CACHE) { ++ $cache_mode='user'; ++} ++// clear cache ++if ($AUTHENTICATED && isset($MYREQUEST['CC']) && $MYREQUEST['CC']) { ++ apc_clear_cache($cache_mode); ++} ++ ++if ($AUTHENTICATED && !empty($MYREQUEST['DU'])) { ++ apc_delete($MYREQUEST['DU']); ++} ++ ++if(!function_exists('apc_cache_info') || !($cache=@apc_cache_info($cache_mode))) { ++ echo "No cache info available. APC does not appear to be running."; ++ exit; ++} ++ ++$cache_user = apc_cache_info('user', 1); ++$mem=apc_sma_info(); ++if(!$cache['num_hits']) { $cache['num_hits']=1; $time++; } // Avoid division by 0 errors on a cache clear ++ ++// don't cache this page ++// ++header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 ++header("Cache-Control: post-check=0, pre-check=0", false); ++header("Pragma: no-cache"); // HTTP/1.0 ++ ++function duration($ts) { ++ global $time; ++ $years = (int)((($time - $ts)/(7*86400))/52.177457); ++ $rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400)); ++ $weeks = (int)(($rem)/(7*86400)); ++ $days = (int)(($rem)/86400) - $weeks*7; ++ $hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24; ++ $mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60; ++ $str = ''; ++ if($years==1) $str .= "$years year, "; ++ if($years>1) $str .= "$years years, "; ++ if($weeks==1) $str .= "$weeks week, "; ++ if($weeks>1) $str .= "$weeks weeks, "; ++ if($days==1) $str .= "$days day,"; ++ if($days>1) $str .= "$days days,"; ++ if($hours == 1) $str .= " $hours hour and"; ++ if($hours>1) $str .= " $hours hours and"; ++ if($mins == 1) $str .= " 1 minute"; ++ else $str .= " $mins minutes"; ++ return $str; ++} ++ ++// create graphics ++// ++function graphics_avail() { ++ return extension_loaded('gd'); ++} ++if (isset($MYREQUEST['IMG'])) ++{ ++ if (!graphics_avail()) { ++ exit(0); ++ } ++ ++ function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) { ++ $r=$diameter/2; ++ $w=deg2rad((360+$start+($end-$start)/2)%360); ++ ++ ++ if (function_exists("imagefilledarc")) { ++ // exists only if GD 2.0.1 is avaliable ++ imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE); ++ imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE); ++ imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); ++ } else { ++ imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2); ++ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); ++ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); ++ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); ++ imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); ++ imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2); ++ } ++ if ($text) { ++ if ($placeindex>0) { ++ imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); ++ imagestring($im,4,$diameter, $placeindex*12,$text,$color1); ++ ++ } else { ++ imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); ++ } ++ } ++ } ++ ++ function text_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$text,$placeindex=0) { ++ $r=$diameter/2; ++ $w=deg2rad((360+$start+($end-$start)/2)%360); ++ ++ if ($placeindex>0) { ++ imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); ++ imagestring($im,4,$diameter, $placeindex*12,$text,$color1); ++ ++ } else { ++ imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); ++ } ++ } ++ ++ function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') { ++ global $col_black; ++ $x1=$x+$w-1; ++ $y1=$y+$h-1; ++ ++ imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black); ++ if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2); ++ else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2); ++ imagerectangle($im, $x, $y1, $x1, $y, $color1); ++ if ($text) { ++ if ($placeindex>0) { ++ ++ if ($placeindex<16) ++ { ++ $px=5; ++ $py=$placeindex*12+6; ++ imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2); ++ imageline($im,$x,$y+$h/2,$px+90,$py,$color2); ++ imagestring($im,2,$px,$py-6,$text,$color1); ++ ++ } else { ++ if ($placeindex<31) { ++ $px=$x+40*2; ++ $py=($placeindex-15)*12+6; ++ } else { ++ $px=$x+40*2+100*intval(($placeindex-15)/15); ++ $py=($placeindex%15)*12+6; ++ } ++ imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2); ++ imageline($im,$x+$w,$y+$h/2,$px,$py,$color2); ++ imagestring($im,2,$px+2,$py-6,$text,$color1); ++ } ++ } else { ++ imagestring($im,4,$x+5,$y1-16,$text,$color1); ++ } ++ } ++ } ++ ++ ++ $size = GRAPH_SIZE; // image size ++ if ($MYREQUEST['IMG']==3) ++ $image = imagecreate(2*$size+150, $size+10); ++ else ++ $image = imagecreate($size+50, $size+10); ++ ++ $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF); ++ $col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30); ++ $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60); ++ $col_black = imagecolorallocate($image, 0, 0, 0); ++ imagecolortransparent($image,$col_white); ++ ++ switch ($MYREQUEST['IMG']) { ++ ++ case 1: ++ $s=$mem['num_seg']*$mem['seg_size']; ++ $a=$mem['avail_mem']; ++ $x=$y=$size/2; ++ $fuzz = 0.000001; ++ ++ // This block of code creates the pie chart. It is a lot more complex than you ++ // would expect because we try to visualize any memory fragmentation as well. ++ $angle_from = 0; ++ $string_placement=array(); ++ for($i=0; $i<$mem['num_seg']; $i++) { ++ $ptr = 0; ++ $free = $mem['block_lists'][$i]; ++ uasort($free, 'block_sort'); ++ foreach($free as $block) { ++ if($block['offset']!=$ptr) { // Used block ++ $angle_to = $angle_from+($block['offset']-$ptr)/$s; ++ if(($angle_to+$fuzz)>1) $angle_to = 1; ++ if( ($angle_to*360) - ($angle_from*360) >= 1) { ++ fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); ++ if (($angle_to-$angle_from)>0.05) { ++ array_push($string_placement, array($angle_from,$angle_to)); ++ } ++ } ++ $angle_from = $angle_to; ++ } ++ $angle_to = $angle_from+($block['size'])/$s; ++ if(($angle_to+$fuzz)>1) $angle_to = 1; ++ if( ($angle_to*360) - ($angle_from*360) >= 1) { ++ fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_green); ++ if (($angle_to-$angle_from)>0.05) { ++ array_push($string_placement, array($angle_from,$angle_to)); ++ } ++ } ++ $angle_from = $angle_to; ++ $ptr = $block['offset']+$block['size']; ++ } ++ if ($ptr < $mem['seg_size']) { // memory at the end ++ $angle_to = $angle_from + ($mem['seg_size'] - $ptr)/$s; ++ if(($angle_to+$fuzz)>1) $angle_to = 1; ++ fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); ++ if (($angle_to-$angle_from)>0.05) { ++ array_push($string_placement, array($angle_from,$angle_to)); ++ } ++ } ++ } ++ foreach ($string_placement as $angle) { ++ text_arc($image,$x,$y,$size,$angle[0]*360,$angle[1]*360,$col_black,bsize($s*($angle[1]-$angle[0]))); ++ } ++ break; ++ ++ case 2: ++ $s=$cache['num_hits']+$cache['num_misses']; ++ $a=$cache['num_hits']; ++ ++ fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s)); ++ fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s)); ++ break; ++ ++ case 3: ++ $s=$mem['num_seg']*$mem['seg_size']; ++ $a=$mem['avail_mem']; ++ $x=130; ++ $y=1; ++ $j=1; ++ ++ // This block of code creates the bar chart. It is a lot more complex than you ++ // would expect because we try to visualize any memory fragmentation as well. ++ for($i=0; $i<$mem['num_seg']; $i++) { ++ $ptr = 0; ++ $free = $mem['block_lists'][$i]; ++ uasort($free, 'block_sort'); ++ foreach($free as $block) { ++ if($block['offset']!=$ptr) { // Used block ++ $h=(GRAPH_SIZE-5)*($block['offset']-$ptr)/$s; ++ if ($h>0) { ++ $j++; ++ if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($block['offset']-$ptr),$j); ++ else fill_box($image,$x,$y,50,$h,$col_black,$col_red); ++ } ++ $y+=$h; ++ } ++ $h=(GRAPH_SIZE-5)*($block['size'])/$s; ++ if ($h>0) { ++ $j++; ++ if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_green,bsize($block['size']),$j); ++ else fill_box($image,$x,$y,50,$h,$col_black,$col_green); ++ } ++ $y+=$h; ++ $ptr = $block['offset']+$block['size']; ++ } ++ if ($ptr < $mem['seg_size']) { // memory at the end ++ $h = (GRAPH_SIZE-5) * ($mem['seg_size'] - $ptr) / $s; ++ if ($h > 0) { ++ fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($mem['seg_size']-$ptr),$j++); ++ } ++ } ++ } ++ break; ++ case 4: ++ $s=$cache['num_hits']+$cache['num_misses']; ++ $a=$cache['num_hits']; ++ ++ fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s)); ++ fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s)); ++ break; ++ ++ } ++ header("Content-type: image/png"); ++ imagepng($image); ++ exit; ++} ++ ++// pretty printer for byte values ++// ++function bsize($s) { ++ foreach (array('','K','M','G') as $i => $k) { ++ if ($s < 1024) break; ++ $s/=1024; ++ } ++ return sprintf("%5.1f %sBytes",$s,$k); ++} ++ ++// sortable table header in "scripts for this host" view ++function sortheader($key,$name,$extra='') { ++ global $MYREQUEST, $MY_SELF_WO_SORT; ++ ++ if ($MYREQUEST['SORT1']==$key) { ++ $MYREQUEST['SORT2'] = $MYREQUEST['SORT2']=='A' ? 'D' : 'A'; ++ } ++ return "$name"; ++ ++} ++ ++// create menu entry ++function menu_entry($ob,$title) { ++ global $MYREQUEST,$MY_SELF; ++ if ($MYREQUEST['OB']!=$ob) { ++ return "
  • $title
  • "; ++ } else if (empty($MYREQUEST['SH'])) { ++ return "
  • $title
  • "; ++ } else { ++ return "
  • $title
  • "; ++ } ++} ++ ++function put_login_link($s="Login") ++{ ++ global $MY_SELF,$MYREQUEST,$AUTHENTICATED; ++ // needs ADMIN_PASSWORD to be changed! ++ // ++ if (!USE_AUTHENTICATION) { ++ return; ++ } else if (ADMIN_PASSWORD=='password') ++ { ++ print <<$s ++EOB; ++ } else if ($AUTHENTICATED) { ++ print <<$s ++EOB; ++ } ++} ++ ++function block_sort($array1, $array2) ++{ ++ if ($array1['offset'] > $array2['offset']) { ++ return 1; ++ } else { ++ return -1; ++ } ++} ++ ++ ++?> ++ ++ ++APC INFO <?php echo $host ?> ++ ++ ++ ++
    ++

    ++ ++
    Opcode Cache
    ++

    ++ ++
    ++
    ++ ++
  • Refresh Data
  • ++EOB; ++echo ++ menu_entry(1,'View Host Stats'), ++ menu_entry(2,'System Cache Entries'); ++if ($AUTHENTICATED) { ++ echo menu_entry(4,'Per-Directory Entries'); ++} ++echo ++ menu_entry(3,'User Cache Entries'), ++ menu_entry(9,'Version Check'); ++ ++if ($AUTHENTICATED) { ++ echo <<Clear $cache_mode Cache ++EOB; ++} ++echo << ++EOB; ++ ++ ++// CONTENT ++echo << ++EOB; ++ ++// MAIN SWITCH STATEMENT ++ ++switch ($MYREQUEST['OB']) { ++ ++ ++ ++ ++ ++// ----------------------------------------------- ++// Host Stats ++// ----------------------------------------------- ++case OB_HOST_STATS: ++ $mem_size = $mem['num_seg']*$mem['seg_size']; ++ $mem_avail= $mem['avail_mem']; ++ $mem_used = $mem_size-$mem_avail; ++ $seg_size = bsize($mem['seg_size']); ++ $req_rate = sprintf("%.2f",($cache['num_hits']+$cache['num_misses'])/($time-$cache['start_time'])); ++ $hit_rate = sprintf("%.2f",($cache['num_hits'])/($time-$cache['start_time'])); ++ $miss_rate = sprintf("%.2f",($cache['num_misses'])/($time-$cache['start_time'])); ++ $insert_rate = sprintf("%.2f",($cache['num_inserts'])/($time-$cache['start_time'])); ++ $req_rate_user = sprintf("%.2f",($cache_user['num_hits']+$cache_user['num_misses'])/($time-$cache_user['start_time'])); ++ $hit_rate_user = sprintf("%.2f",($cache_user['num_hits'])/($time-$cache_user['start_time'])); ++ $miss_rate_user = sprintf("%.2f",($cache_user['num_misses'])/($time-$cache_user['start_time'])); ++ $insert_rate_user = sprintf("%.2f",($cache_user['num_inserts'])/($time-$cache_user['start_time'])); ++ $apcversion = phpversion('apc'); ++ $phpversion = phpversion(); ++ $number_files = $cache['num_entries']; ++ $size_files = bsize($cache['mem_size']); ++ $number_vars = $cache_user['num_entries']; ++ $size_vars = bsize($cache_user['mem_size']); ++ $i=0; ++ echo <<< EOB ++

    General Cache Information

    ++ ++ ++ ++EOB; ++ ++ if(!empty($_SERVER['SERVER_NAME'])) ++ echo "\n"; ++ if(!empty($_SERVER['SERVER_SOFTWARE'])) ++ echo "\n"; ++ ++ echo << ++EOB; ++ echo ''; ++ echo ''; ++ echo ''; ++ echo <<
    APC Version$apcversion
    PHP Version$phpversion
    APC Host{$_SERVER['SERVER_NAME']} $host
    Server Software{$_SERVER['SERVER_SOFTWARE']}
    Shared Memory{$mem['num_seg']} Segment(s) with $seg_size ++
    ({$cache['memory_type']} memory, {$cache['locking_type']} locking) ++
    Start Time',date(DATE_FORMAT,$cache['start_time']),'
    Uptime',duration($cache['start_time']),'
    File Upload Support',$cache['file_upload_progress'],'
    ++
    ++ ++

    File Cache Information

    ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    Cached Files$number_files ($size_files)
    Hits{$cache['num_hits']}
    Misses{$cache['num_misses']}
    Request Rate (hits, misses)$req_rate cache requests/second
    Hit Rate$hit_rate cache requests/second
    Miss Rate$miss_rate cache requests/second
    Insert Rate$insert_rate cache requests/second
    Cache full count{$cache['expunges']}
    ++
    ++ ++

    User Cache Information

    ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
    Cached Variables$number_vars ($size_vars)
    Hits{$cache_user['num_hits']}
    Misses{$cache_user['num_misses']}
    Request Rate (hits, misses)$req_rate_user cache requests/second
    Hit Rate$hit_rate_user cache requests/second
    Miss Rate$miss_rate_user cache requests/second
    Insert Rate$insert_rate_user cache requests/second
    Cache full count{$cache_user['expunges']}
    ++
    ++ ++

    Runtime Settings

    ++EOB; ++ ++ $j = 0; ++ foreach (ini_get_all('apc') as $k => $v) { ++ echo "\n"; ++ $j = 1 - $j; ++ } ++ ++ if($mem['num_seg']>1 || $mem['num_seg']==1 && count($mem['block_lists'][0])>1) ++ $mem_note = "Memory Usage
    (multiple slices indicate fragments)"; ++ else ++ $mem_note = "Memory Usage"; ++ ++ echo <<< EOB ++
    ",$k,"",str_replace(',',',
    ',$v['local_value']),"
    ++
    ++ ++

    Host Status Diagrams

    ++ ++EOB; ++ $size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10); ++ echo << ++ ++ ++ ++EOB; ++ ++ echo ++ graphics_avail() ? ++ ''. ++ "". ++ "\n" ++ : "", ++ '', ++ '\n", ++ '\n", ++ '', ++ '', ++ '\n", ++ '\n"; ++ echo <<< EOB ++ ++
    $mem_noteHits & Misses
    \"\"\"\"
     Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size)," Hits: ',$cache['num_hits'].sprintf(" (%.1f%%)",$cache['num_hits']*100/($cache['num_hits']+$cache['num_misses'])),"
     Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size)," Misses: ',$cache['num_misses'].sprintf(" (%.1f%%)",$cache['num_misses']*100/($cache['num_hits']+$cache['num_misses'])),"
    ++ ++
    ++

    Detailed Memory Usage and Fragmentation

    ++ ++ ++ ++ ++EOB; ++ if(isset($mem['adist'])) { ++ foreach($mem['adist'] as $i=>$v) { ++ $cur = pow(2,$i); $nxt = pow(2,$i+1)-1; ++ if($i==0) $range = "1"; ++ else $range = "$cur - $nxt"; ++ echo "\n"; ++ } ++ } ++ echo <<

    ++EOB; ++ ++ // Fragementation: (freeseg - 1) / total_seg ++ $nseg = $freeseg = $fragsize = $freetotal = 0; ++ for($i=0; $i<$mem['num_seg']; $i++) { ++ $ptr = 0; ++ foreach($mem['block_lists'][$i] as $block) { ++ if ($block['offset'] != $ptr) { ++ ++$nseg; ++ } ++ $ptr = $block['offset'] + $block['size']; ++ /* Only consider blocks <5M for the fragmentation % */ ++ if($block['size']<(5*1024*1024)) $fragsize+=$block['size']; ++ $freetotal+=$block['size']; ++ } ++ $freeseg += count($mem['block_lists'][$i]); ++ } ++ ++ if ($freeseg > 1) { ++ $frag = sprintf("%.2f%% (%s out of %s in %d fragments)", ($fragsize/$freetotal)*100,bsize($fragsize),bsize($freetotal),$freeseg); ++ } else { ++ $frag = "0%"; ++ } ++ ++ if (graphics_avail()) { ++ $size='width='.(2*GRAPH_SIZE+150).' height='.(GRAPH_SIZE+10); ++ echo << ++EOB; ++ } ++ echo <<Fragmentation: $frag ++
    $range$v
    ++
    ++EOB; ++ ++ break; ++ ++ ++// ----------------------------------------------- ++// User Cache Entries ++// ----------------------------------------------- ++case OB_USER_CACHE: ++ if (!$AUTHENTICATED) { ++ echo '
    You need to login to see the user values here!
     
    '; ++ put_login_link("Login now!"); ++ echo '
    '; ++ break; ++ } ++ $fieldname='info'; ++ $fieldheading='User Entry Label'; ++ $fieldkey='info'; ++ ++// ----------------------------------------------- ++// System Cache Entries ++// ----------------------------------------------- ++case OB_SYS_CACHE: ++ if (!isset($fieldname)) ++ { ++ $fieldname='filename'; ++ $fieldheading='Script Filename'; ++ if(ini_get("apc.stat")) $fieldkey='inode'; ++ else $fieldkey='filename'; ++ } ++ if (!empty($MYREQUEST['SH'])) ++ { ++ echo <<< EOB ++
    ++ ++EOB; ++ ++ $m=0; ++ foreach($scope_list as $j => $list) { ++ foreach($cache[$list] as $i => $entry) { ++ if (md5($entry[$fieldkey])!=$MYREQUEST['SH']) continue; ++ foreach($entry as $k => $value) { ++ if (!$AUTHENTICATED) { ++ // hide all path entries if not logged in ++ $value=preg_replace('/^.*(\\/|\\\\)/','<hidden>/',$value); ++ } ++ ++ if ($k == "num_hits") { ++ $value=sprintf("%s (%.2f%%)",$value,$value*100/$cache['num_hits']); ++ } ++ if ($k == 'deletion_time') { ++ if(!$entry['deletion_time']) $value = "None"; ++ } ++ echo ++ "", ++ "", ++ "", ++ ""; ++ $m=1-$m; ++ } ++ if($fieldkey=='info') { ++ echo "\n"; ++ } ++ break; ++ } ++ } ++ ++ echo <<
    AttributeValue
    ",ucwords(preg_replace("/_/"," ",$k)),"",(preg_match("/time/",$k) && $value!='None') ? date(DATE_FORMAT,$value) : htmlspecialchars($value, ENT_QUOTES, 'UTF-8'),"
    Stored Value
    ";
    ++					$output = var_export(apc_fetch($entry[$fieldkey]),true);
    ++					echo htmlspecialchars($output, ENT_QUOTES, 'UTF-8');
    ++					echo "
    ++
    ++EOB; ++ break; ++ } ++ ++ $cols=6; ++ echo <<
    Scope: ++ ++ ", ++ ", Sorting:', ++ '', ++ '', ++ '  Search: ', ++ ' ', ++ '
    '; ++ ++ if (isset($MYREQUEST['SEARCH'])) { ++ // Don't use preg_quote because we want the user to be able to specify a ++ // regular expression subpattern. ++ $MYREQUEST['SEARCH'] = '/'.str_replace('/', '\\/', $MYREQUEST['SEARCH']).'/i'; ++ if (preg_match($MYREQUEST['SEARCH'], 'test') === false) { ++ echo '
    Error: enter a valid regular expression as a search query.
    '; ++ break; ++ } ++ } ++ ++ echo ++ '
    ', ++ '', ++ '', ++ '', ++ '', ++ '', ++ '', ++ ''; ++ ++ if($fieldname=='info') { ++ $cols+=2; ++ echo ''; ++ } ++ echo ''; ++ ++ // builds list with alpha numeric sortable keys ++ // ++ $list = array(); ++ foreach($cache[$scope_list[$MYREQUEST['SCOPE']]] as $i => $entry) { ++ switch($MYREQUEST['SORT1']) { ++ case 'A': $k=sprintf('%015d-',$entry['access_time']); break; ++ case 'H': $k=sprintf('%015d-',$entry['num_hits']); break; ++ case 'Z': $k=sprintf('%015d-',$entry['mem_size']); break; ++ case 'M': $k=sprintf('%015d-',$entry['mtime']); break; ++ case 'C': $k=sprintf('%015d-',$entry['creation_time']); break; ++ case 'T': $k=sprintf('%015d-',$entry['ttl']); break; ++ case 'D': $k=sprintf('%015d-',$entry['deletion_time']); break; ++ case 'S': $k=''; break; ++ } ++ if (!$AUTHENTICATED) { ++ // hide all path entries if not logged in ++ $list[$k.$entry[$fieldname]]=preg_replace('/^.*(\\/|\\\\)/','*hidden*/',$entry); ++ } else { ++ $list[$k.$entry[$fieldname]]=$entry; ++ } ++ } ++ ++ if ($list) { ++ ++ // sort list ++ // ++ switch ($MYREQUEST['SORT2']) { ++ case "A": krsort($list); break; ++ case "D": ksort($list); break; ++ } ++ ++ // output list ++ $i=0; ++ foreach($list as $k => $entry) { ++ if(!$MYREQUEST['SEARCH'] || preg_match($MYREQUEST['SEARCH'], $entry[$fieldname]) != 0) { ++ $field_value = htmlentities(strip_tags($entry[$fieldname],''), ENT_QUOTES, 'UTF-8'); ++ echo ++ '', ++ "', ++ '', ++ '', ++ '', ++ '', ++ ''; ++ ++ if($fieldname=='info') { ++ if($entry['ttl']) ++ echo ''; ++ else ++ echo ''; ++ } ++ if ($entry['deletion_time']) { ++ ++ echo ''; ++ } else if ($MYREQUEST['OB'] == OB_USER_CACHE) { ++ ++ echo ''; ++ } else { ++ echo ''; ++ } ++ echo ''; ++ $i++; ++ if ($i == $MYREQUEST['COUNT']) ++ break; ++ } ++ } ++ ++ } else { ++ echo ''; ++ } ++ echo <<< EOB ++
    ',sortheader('S',$fieldheading, "&OB=".$MYREQUEST['OB']),'',sortheader('H','Hits', "&OB=".$MYREQUEST['OB']),'',sortheader('Z','Size', "&OB=".$MYREQUEST['OB']),'',sortheader('A','Last accessed',"&OB=".$MYREQUEST['OB']),'',sortheader('M','Last modified',"&OB=".$MYREQUEST['OB']),'',sortheader('C','Created at', "&OB=".$MYREQUEST['OB']),'',sortheader('T','Timeout',"&OB=".$MYREQUEST['OB']),'',sortheader('D','Deleted at',"&OB=".$MYREQUEST['OB']),'
    ",$field_value,'',$entry['num_hits'],'',$entry['mem_size'],'',date(DATE_FORMAT,$entry['access_time']),'',date(DATE_FORMAT,$entry['mtime']),'',date(DATE_FORMAT,$entry['creation_time']),''.$entry['ttl'].' secondsNone', date(DATE_FORMAT,$entry['deletion_time']), ''; ++ echo '[Delete Now]'; ++ echo '  
    No data
    ++EOB; ++ ++ if ($list && $i < count($list)) { ++ echo "",count($list)-$i,' more available...'; ++ } ++ ++ echo <<< EOB ++
    ++EOB; ++ break; ++ ++ ++// ----------------------------------------------- ++// Per-Directory System Cache Entries ++// ----------------------------------------------- ++case OB_SYS_CACHE_DIR: ++ if (!$AUTHENTICATED) { ++ break; ++ } ++ ++ echo <<
    Scope: ++ ++ ", ++ ", Sorting:', ++ '', ++ '', ++ ", Group By Dir Level:', ++ ' ', ++ '
    ', ++ ++ '
    ', ++ '', ++ '', ++ '', ++ '', ++ '', ++ '', ++ '', ++ ''; ++ ++ // builds list with alpha numeric sortable keys ++ // ++ $tmp = $list = array(); ++ foreach($cache[$scope_list[$MYREQUEST['SCOPE']]] as $entry) { ++ $n = dirname($entry['filename']); ++ if ($MYREQUEST['AGGR'] > 0) { ++ $n = preg_replace("!^(/?(?:[^/\\\\]+[/\\\\]){".($MYREQUEST['AGGR']-1)."}[^/\\\\]*).*!", "$1", $n); ++ } ++ if (!isset($tmp[$n])) { ++ $tmp[$n] = array('hits'=>0,'size'=>0,'ents'=>0); ++ } ++ $tmp[$n]['hits'] += $entry['num_hits']; ++ $tmp[$n]['size'] += $entry['mem_size']; ++ ++$tmp[$n]['ents']; ++ } ++ ++ foreach ($tmp as $k => $v) { ++ switch($MYREQUEST['SORT1']) { ++ case 'A': $kn=sprintf('%015d-',$v['size'] / $v['ents']);break; ++ case 'T': $kn=sprintf('%015d-',$v['ents']); break; ++ case 'H': $kn=sprintf('%015d-',$v['hits']); break; ++ case 'Z': $kn=sprintf('%015d-',$v['size']); break; ++ case 'C': $kn=sprintf('%015d-',$v['hits'] / $v['ents']);break; ++ case 'S': $kn = $k; break; ++ } ++ $list[$kn.$k] = array($k, $v['ents'], $v['hits'], $v['size']); ++ } ++ ++ if ($list) { ++ ++ // sort list ++ // ++ switch ($MYREQUEST['SORT2']) { ++ case "A": krsort($list); break; ++ case "D": ksort($list); break; ++ } ++ ++ // output list ++ $i = 0; ++ foreach($list as $entry) { ++ echo ++ '', ++ "', ++ '', ++ '', ++ '', ++ '', ++ '', ++ ''; ++ ++ if (++$i == $MYREQUEST['COUNT']) break; ++ } ++ ++ } else { ++ echo ''; ++ } ++ echo <<< EOB ++
    ',sortheader('S','Directory Name', "&OB=".$MYREQUEST['OB']),'',sortheader('T','Number of Files',"&OB=".$MYREQUEST['OB']),'',sortheader('H','Total Hits', "&OB=".$MYREQUEST['OB']),'',sortheader('Z','Total Size', "&OB=".$MYREQUEST['OB']),'',sortheader('C','Avg. Hits', "&OB=".$MYREQUEST['OB']),'',sortheader('A','Avg. Size', "&OB=".$MYREQUEST['OB']),'
    ",$entry[0],'',$entry[1],'',$entry[2],'',$entry[3],'',round($entry[2] / $entry[1]),'',round($entry[3] / $entry[1]),'
    No data
    ++EOB; ++ ++ if ($list && $i < count($list)) { ++ echo "",count($list)-$i,' more available...'; ++ } ++ ++ echo <<< EOB ++
    ++EOB; ++ break; ++ ++// ----------------------------------------------- ++// Version check ++// ----------------------------------------------- ++case OB_VERSION_CHECK: ++ echo <<

    APC Version Information

    ++ ++ ++ ++ ++EOB; ++ if (defined('PROXY')) { ++ $ctxt = stream_context_create( array( 'http' => array( 'proxy' => PROXY, 'request_fulluri' => True ) ) ); ++ $rss = @file_get_contents("http://pecl.php.net/feeds/pkg_apc.rss", False, $ctxt); ++ } else { ++ $rss = @file_get_contents("http://pecl.php.net/feeds/pkg_apc.rss"); ++ } ++ if (!$rss) { ++ echo ''; ++ } else { ++ $apcversion = phpversion('apc'); ++ ++ preg_match('!APC ([0-9.]+)!', $rss, $match); ++ echo ''; ++ echo ''; + } ++ echo <<< EOB ++
    Unable to fetch version information.
    '; ++ if (version_compare($apcversion, $match[1], '>=')) { ++ echo '
    You are running the latest version of APC ('.$apcversion.')
    '; ++ $i = 3; ++ } else { ++ echo '
    You are running an older version of APC ('.$apcversion.'), ++ newer version '.$match[1].' is available at ++ http://pecl.php.net/package/APC/'.$match[1].' ++
    '; ++ $i = -1; ++ } ++ echo '

    Change Log:


    '; ++ ++ preg_match_all('!<(title|description)>([^<]+)!', $rss, $match); ++ next($match[2]); next($match[2]); ++ ++ while (list(,$v) = each($match[2])) { ++ list(,$ver) = explode(' ', $v, 2); ++ if ($i < 0 && version_compare($apcversion, $ver, '>=')) { ++ break; ++ } else if (!$i--) { ++ break; + } -+ $ptr = $block['offset'] + $block['size']; -+ /* Only consider blocks <5M for the fragmentation % */ -+ if($block['size']<(5*1024*1024)) $fragsize+=$block['size']; -+ $freetotal+=$block['size']; ++ echo "".htmlspecialchars($v, ENT_QUOTES, 'UTF-8')."
    "; ++ echo nl2br(htmlspecialchars(current($match[2]), ENT_QUOTES, 'UTF-8'))."
    "; ++ next($match[2]); + } -+ $freeseg += count($mem['block_lists'][$i]); ++ echo '
    ++ ++EOB; ++ break; ++ ++} ++ ++echo <<< EOB ++ ++EOB; ++ ++?> ++ ++ ++ ++ +diff -Naur a/ext/apc/apc_php.h b/ext/apc/apc_php.h +--- a/ext/apc/apc_php.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_php.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,81 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | George Schlossnagle | ++ | Rasmus Lerdorf | ++ | Arun C. Murthy | ++ | Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ ++ ++ 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_php.h 313808 2011-07-28 06:17:10Z gopalv $ */ ++ ++#ifndef APC_PHP_H ++#define APC_PHP_H ++ ++/* ++ * The purpose of this header file is to include all PHP and Zend headers that ++ * are typically needed elsewhere in APC. This makes it easy to insure that ++ * all required headers are available. ++ */ ++ ++#include "php.h" ++#include "zend.h" ++#include "zend_API.h" ++#include "zend_compile.h" ++#include "zend_hash.h" ++#include "zend_extensions.h" ++ ++#if ZEND_MODULE_API_NO >= 20100409 ++#define ZEND_ENGINE_2_4 ++#endif ++#if ZEND_MODULE_API_NO > 20060613 ++#define ZEND_ENGINE_2_3 ++#endif ++#if ZEND_MODULE_API_NO > 20050922 ++#define ZEND_ENGINE_2_2 ++#endif ++#if ZEND_MODULE_API_NO > 20050921 ++#define ZEND_ENGINE_2_1 ++#endif ++#ifdef ZEND_ENGINE_2_1 ++#include "zend_vm.h" ++#endif ++ ++#ifndef IS_CONSTANT_TYPE_MASK ++#define IS_CONSTANT_TYPE_MASK (~IS_CONSTANT_INDEX) ++#endif ++ ++#include "rfc1867.h" ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_php_pcre.h b/ext/apc/apc_php_pcre.h +--- a/ext/apc/apc_php_pcre.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_php_pcre.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,98 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | APC/PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-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. | ++ +----------------------------------------------------------------------+ ++ | Author: Andrei Zmievski | ++ +----------------------------------------------------------------------+ ++ */ ++ ++/* $Id: apc_php_pcre.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef PHP_PCRE_H ++#define PHP_PCRE_H ++ ++#if HAVE_PCRE || HAVE_BUNDLED_PCRE ++ ++#if HAVE_BUNDLED_PCRE ++#include "ext/pcre/pcrelib/pcre.h" ++#else ++#include "pcre.h" ++#endif ++ ++#if HAVE_LOCALE_H ++#include ++#endif ++ ++PHP_FUNCTION(preg_match); ++PHP_FUNCTION(preg_match_all); ++PHP_FUNCTION(preg_replace); ++PHP_FUNCTION(preg_replace_callback); ++PHP_FUNCTION(preg_split); ++PHP_FUNCTION(preg_quote); ++PHP_FUNCTION(preg_grep); ++ ++PHPAPI char *php_pcre_replace(char *regex, int regex_len, char *subject, int subject_len, zval *replace_val, int is_callable_replace, int *result_len, int limit, int *replace_count TSRMLS_DC); ++PHPAPI pcre* pcre_get_compiled_regex(char *regex, pcre_extra **extra, int *options TSRMLS_DC); ++PHPAPI pcre* pcre_get_compiled_regex_ex(char *regex, pcre_extra **extra, int *preg_options, int *coptions TSRMLS_DC); ++ ++extern zend_module_entry pcre_module_entry; ++#define pcre_module_ptr &pcre_module_entry ++ ++typedef struct { ++ pcre *re; ++ pcre_extra *extra; ++ int preg_options; ++#if HAVE_SETLOCALE ++ char *locale; ++ unsigned const char *tables; ++#endif ++ int compile_options; ++ int refcount; ++} pcre_cache_entry; ++ ++PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_len TSRMLS_DC); ++ ++PHPAPI void php_pcre_match_impl( pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value, ++ zval *subpats, int global, int use_flags, long flags, long start_offset TSRMLS_DC); ++ ++PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value, ++ int is_callable_replace, int *result_len, int limit, int *replace_count TSRMLS_DC); ++ ++PHPAPI void php_pcre_split_impl( pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value, ++ long limit_val, long flags TSRMLS_DC); ++ ++PHPAPI void php_pcre_grep_impl( pcre_cache_entry *pce, zval *input, zval *return_value, ++ long flags TSRMLS_DC); ++ ++ZEND_BEGIN_MODULE_GLOBALS(pcre) ++ HashTable pcre_cache; ++ long backtrack_limit; ++ long recursion_limit; ++ int error_code; ++ZEND_END_MODULE_GLOBALS(pcre) ++ ++#ifdef ZTS ++# define PCRE_G(v) TSRMG(pcre_globals_id, zend_pcre_globals *, v) ++#else ++# define PCRE_G(v) (pcre_globals.v) ++#endif ++ ++#else ++ ++#define pcre_module_ptr NULL ++ ++#endif /* HAVE_PCRE || HAVE_BUNDLED_PCRE */ ++ ++#define phpext_pcre_ptr pcre_module_ptr ++ ++#endif /* PHP_PCRE_H */ +diff -Naur a/ext/apc/apc_pool.c b/ext/apc/apc_pool.c +--- a/ext/apc/apc_pool.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_pool.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,507 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Yahoo! Inc. in 2008. ++ ++ Future revisions and derivatives of this source code must acknowledge ++ Yahoo! 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_pool.c 307555 2011-01-18 07:17:21Z gopalv $ */ ++ ++ ++#include "apc_pool.h" ++#include ++ ++#ifdef HAVE_VALGRIND_MEMCHECK_H ++#include ++#endif ++ ++ ++/* {{{ forward references */ ++static apc_pool* apc_unpool_create(apc_pool_type type, apc_malloc_t, apc_free_t, apc_protect_t, apc_unprotect_t TSRMLS_DC); ++static apc_pool* apc_realpool_create(apc_pool_type type, apc_malloc_t, apc_free_t, apc_protect_t, apc_unprotect_t TSRMLS_DC); ++/* }}} */ ++ ++/* {{{ apc_pool_create */ ++apc_pool* apc_pool_create(apc_pool_type pool_type, ++ apc_malloc_t allocate, ++ apc_free_t deallocate, ++ apc_protect_t protect, ++ apc_unprotect_t unprotect ++ TSRMLS_DC) ++{ ++ if(pool_type == APC_UNPOOL) { ++ return apc_unpool_create(pool_type, allocate, deallocate, ++ protect, unprotect TSRMLS_CC); ++ } ++ ++ return apc_realpool_create(pool_type, allocate, deallocate, ++ protect, unprotect TSRMLS_CC); ++} ++/* }}} */ ++ ++/* {{{ apc_pool_destroy */ ++void apc_pool_destroy(apc_pool *pool TSRMLS_DC) ++{ ++ apc_free_t deallocate = pool->deallocate; ++ apc_pcleanup_t cleanup = pool->cleanup; ++ ++ cleanup(pool TSRMLS_CC); ++ deallocate(pool TSRMLS_CC); ++} ++/* }}} */ ++ ++/* {{{ apc_unpool implementation */ ++ ++typedef struct _apc_unpool apc_unpool; ++ ++struct _apc_unpool { ++ apc_pool parent; ++ /* apc_unpool is a lie! */ ++}; ++ ++static void* apc_unpool_alloc(apc_pool* pool, size_t size TSRMLS_DC) ++{ ++ apc_unpool *upool = (apc_unpool*)pool; ++ ++ apc_malloc_t allocate = upool->parent.allocate; ++ ++ upool->parent.size += size; ++ upool->parent.used += size; ++ ++ return allocate(size TSRMLS_CC); ++} ++ ++static void apc_unpool_free(apc_pool* pool, void *ptr TSRMLS_DC) ++{ ++ apc_unpool *upool = (apc_unpool*) pool; ++ ++ apc_free_t deallocate = upool->parent.deallocate; ++ ++ deallocate(ptr TSRMLS_CC); ++} ++ ++static void apc_unpool_cleanup(apc_pool* pool TSRMLS_DC) ++{ ++} ++ ++static apc_pool* apc_unpool_create(apc_pool_type type, ++ apc_malloc_t allocate, apc_free_t deallocate, ++ apc_protect_t protect, apc_unprotect_t unprotect ++ TSRMLS_DC) ++{ ++ apc_unpool* upool = allocate(sizeof(apc_unpool) TSRMLS_CC); ++ ++ if (!upool) { ++ return NULL; ++ } ++ ++ upool->parent.type = type; ++ upool->parent.allocate = allocate; ++ upool->parent.deallocate = deallocate; ++ ++ upool->parent.protect = protect; ++ upool->parent.unprotect = unprotect; ++ ++ upool->parent.palloc = apc_unpool_alloc; ++ upool->parent.pfree = apc_unpool_free; ++ ++ upool->parent.cleanup = apc_unpool_cleanup; ++ ++ upool->parent.used = 0; ++ upool->parent.size = 0; ++ ++ return &(upool->parent); ++} ++/* }}} */ ++ ++ ++/*{{{ apc_realpool implementation */ ++ ++/* {{{ typedefs */ ++typedef struct _pool_block ++{ ++ size_t avail; ++ size_t capacity; ++ unsigned char *mark; ++ struct _pool_block *next; ++ unsigned :0; /* this should align to word */ ++ /* data comes here */ ++}pool_block; ++ ++/* ++ parts in ? are optional and turned on for fun, memory loss, ++ and for something else that I forgot about ... ah, debugging ++ ++ |--------> data[] |<-- non word boundary (too) ++ +-------------+--------------+-----------+-------------+-------------->>> ++ | pool_block | ?sizeinfo<1> | block<1> | ?redzone<1> | ?sizeinfo<2> ++ | | (size_t) | | padded left | ++ +-------------+--------------+-----------+-------------+-------------->>> ++ */ ++ ++typedef struct _apc_realpool apc_realpool; ++ ++struct _apc_realpool ++{ ++ struct _apc_pool parent; ++ ++ size_t dsize; ++ void *owner; ++ ++ unsigned long count; ++ ++ pool_block *head; ++ pool_block first; ++}; ++ ++/* }}} */ ++ ++/* {{{ redzone code */ ++static const unsigned char decaff[] = { ++ 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad, ++ 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad, ++ 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad, ++ 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad ++}; ++ ++/* a redzone is at least 4 (0xde,0xca,0xc0,0xff) bytes */ ++#define REDZONE_SIZE(size) \ ++ ((ALIGNWORD((size)) > ((size) + 4)) ? \ ++ (ALIGNWORD((size)) - (size)) : /* does not change realsize */\ ++ ALIGNWORD((size)) - (size) + ALIGNWORD((sizeof(char)))) /* adds 1 word to realsize */ ++ ++#define SIZEINFO_SIZE ALIGNWORD(sizeof(size_t)) ++ ++#define MARK_REDZONE(block, redsize) do {\ ++ memcpy(block, decaff, redsize );\ ++ } while(0) ++ ++#define CHECK_REDZONE(block, redsize) (memcmp(block, decaff, redsize) == 0) ++ ++/* }}} */ ++ ++#define INIT_POOL_BLOCK(rpool, entry, size) do {\ ++ (entry)->avail = (entry)->capacity = (size);\ ++ (entry)->mark = ((unsigned char*)(entry)) + ALIGNWORD(sizeof(pool_block));\ ++ (entry)->next = (rpool)->head;\ ++ (rpool)->head = (entry);\ ++} while(0) ++ ++/* {{{ create_pool_block */ ++static pool_block* create_pool_block(apc_realpool *rpool, size_t size TSRMLS_DC) ++{ ++ apc_malloc_t allocate = rpool->parent.allocate; ++ ++ size_t realsize = sizeof(pool_block) + ALIGNWORD(size); ++ ++ pool_block* entry = allocate(realsize TSRMLS_CC); ++ ++ if (!entry) { ++ return NULL; ++ } ++ ++ INIT_POOL_BLOCK(rpool, entry, size); ++ ++ rpool->parent.size += realsize; ++ ++ rpool->count++; ++ ++ return entry; ++} ++/* }}} */ ++ ++/* {{{ apc_realpool_alloc */ ++static void* apc_realpool_alloc(apc_pool *pool, size_t size TSRMLS_DC) ++{ ++ apc_realpool *rpool = (apc_realpool*)pool; ++ unsigned char *p = NULL; ++ size_t realsize = ALIGNWORD(size); ++ size_t poolsize; ++ unsigned char *redzone = NULL; ++ size_t redsize = 0; ++ size_t *sizeinfo= NULL; ++ pool_block *entry = NULL; ++ unsigned long i; ++ ++ if(APC_POOL_HAS_REDZONES(pool)) { ++ redsize = REDZONE_SIZE(size); /* redsize might be re-using word size padding */ ++ realsize = size + redsize; /* recalculating realsize */ ++ } else { ++ redsize = realsize - size; /* use padding space */ ++ } ++ ++ if(APC_POOL_HAS_SIZEINFO(pool)) { ++ realsize += ALIGNWORD(sizeof(size_t)); ++ } ++ ++ /* minimize look-back, a value of 8 seems to give similar fill-ratios (+2%) ++ * as looping through the entire list. And much faster in allocations. */ ++ for(entry = rpool->head, i = 0; entry != NULL && (i < 8); entry = entry->next, i++) { ++ if(entry->avail >= realsize) { ++ goto found; ++ } ++ } ++ ++ /* upgrade the pool type to reduce overhead */ ++ if(rpool->count > 4 && rpool->dsize < 4096) { ++ rpool->dsize = 4096; ++ } else if(rpool->count > 8 && rpool->dsize < 8192) { ++ rpool->dsize = 8192; ++ } ++ ++ poolsize = ALIGNSIZE(realsize, rpool->dsize); ++ ++ entry = create_pool_block(rpool, poolsize TSRMLS_CC); ++ ++ if(!entry) { ++ return NULL; ++ } ++ ++found: ++ p = entry->mark; ++ ++ if(APC_POOL_HAS_SIZEINFO(pool)) { ++ sizeinfo = (size_t*)p; ++ p += SIZEINFO_SIZE; ++ *sizeinfo = size; ++ } ++ ++ redzone = p + size; ++ ++ if(APC_POOL_HAS_REDZONES(pool)) { ++ MARK_REDZONE(redzone, redsize); ++ } ++ ++#ifdef VALGRIND_MAKE_MEM_NOACCESS ++ if(redsize != 0) { ++ VALGRIND_MAKE_MEM_NOACCESS(redzone, redsize); ++ } ++#endif ++ ++ entry->avail -= realsize; ++ entry->mark += realsize; ++ pool->used += realsize; ++ ++#ifdef VALGRIND_MAKE_MEM_UNDEFINED ++ /* need to write before reading data off this */ ++ VALGRIND_MAKE_MEM_UNDEFINED(p, size); ++#endif ++ ++ return (void*)p; ++} ++/* }}} */ ++ ++/* {{{ apc_realpool_check_integrity */ ++/* ++ * Checking integrity at runtime, does an ++ * overwrite check only when the sizeinfo ++ * is set. ++ * ++ * Marked as used in gcc, so that this function ++ * is accessible from gdb, eventhough it is never ++ * used in code in non-debug builds. ++ */ ++static APC_USED int apc_realpool_check_integrity(apc_realpool *rpool) ++{ ++ apc_pool *pool = &(rpool->parent); ++ pool_block *entry; ++ size_t *sizeinfo = NULL; ++ unsigned char *start; ++ size_t realsize; ++ unsigned char *redzone; ++ size_t redsize; ++ ++ for(entry = rpool->head; entry != NULL; entry = entry->next) { ++ start = (unsigned char *)entry + ALIGNWORD(sizeof(pool_block)); ++ if((entry->mark - start) != (entry->capacity - entry->avail)) { ++ return 0; ++ } ++ } ++ ++ if(!APC_POOL_HAS_REDZONES(pool) || ++ !APC_POOL_HAS_SIZEINFO(pool)) { ++ (void)pool; /* remove unused warning */ ++ return 1; ++ } ++ ++ for(entry = rpool->head; entry != NULL; entry = entry->next) { ++ start = (unsigned char *)entry + ALIGNWORD(sizeof(pool_block)); ++ ++ while(start < entry->mark) { ++ sizeinfo = (size_t*)start; ++ /* redzone starts where real data ends, in a non-word boundary ++ * redsize is at least 4 bytes + whatever's needed to make it ++ * to another word boundary. ++ */ ++ redzone = start + SIZEINFO_SIZE + (*sizeinfo); ++ redsize = REDZONE_SIZE(*sizeinfo); ++#ifdef VALGRIND_MAKE_MEM_DEFINED ++ VALGRIND_MAKE_MEM_DEFINED(redzone, redsize); ++#endif ++ if(!CHECK_REDZONE(redzone, redsize)) ++ { ++ /* ++ fprintf(stderr, "Redzone check failed for %p\n", ++ start + ALIGNWORD(sizeof(size_t)));*/ ++ return 0; ++ } ++#ifdef VALGRIND_MAKE_MEM_NOACCESS ++ VALGRIND_MAKE_MEM_NOACCESS(redzone, redsize); ++#endif ++ realsize = SIZEINFO_SIZE + *sizeinfo + redsize; ++ start += realsize; ++ } ++ } ++ ++ return 1; ++} ++/* }}} */ ++ ++/* {{{ apc_realpool_free */ ++/* ++ * free does not do anything other than ++ * check for redzone values when free'ing ++ * data areas. ++ */ ++static void apc_realpool_free(apc_pool *pool, void *p TSRMLS_DC) ++{ ++} ++/* }}} */ ++ ++static void apc_realpool_cleanup(apc_pool *pool TSRMLS_DC) ++{ ++ pool_block *entry; ++ pool_block *tmp; ++ apc_realpool *rpool = (apc_realpool*)pool; ++ apc_free_t deallocate = pool->deallocate; ++ ++ assert(apc_realpool_check_integrity(rpool)!=0); ++ ++ entry = rpool->head; ++ ++ while(entry->next != NULL) { ++ tmp = entry->next; ++ deallocate(entry TSRMLS_CC); ++ entry = tmp; ++ } ++} ++ ++/* {{{ apc_realpool_create */ ++static apc_pool* apc_realpool_create(apc_pool_type type, apc_malloc_t allocate, apc_free_t deallocate, ++ apc_protect_t protect, apc_unprotect_t unprotect ++ TSRMLS_DC) ++{ ++ ++ size_t dsize = 0; ++ apc_realpool *rpool; ++ ++ switch(type & APC_POOL_SIZE_MASK) { ++ case APC_SMALL_POOL: ++ dsize = 512; ++ break; ++ ++ case APC_LARGE_POOL: ++ dsize = 8192; ++ break; ++ ++ case APC_MEDIUM_POOL: ++ dsize = 4096; ++ break; ++ ++ default: ++ return NULL; ++ } ++ ++ rpool = (apc_realpool*)allocate((sizeof(apc_realpool) + ALIGNWORD(dsize)) TSRMLS_CC); ++ ++ if(!rpool) { ++ return NULL; ++ } ++ ++ rpool->parent.type = type; ++ ++ rpool->parent.allocate = allocate; ++ rpool->parent.deallocate = deallocate; ++ ++ rpool->parent.size = sizeof(apc_realpool) + ALIGNWORD(dsize); ++ ++ rpool->parent.palloc = apc_realpool_alloc; ++ rpool->parent.pfree = apc_realpool_free; ++ ++ rpool->parent.protect = protect; ++ rpool->parent.unprotect = unprotect; ++ ++ rpool->parent.cleanup = apc_realpool_cleanup; ++ ++ rpool->dsize = dsize; ++ rpool->head = NULL; ++ rpool->count = 0; ++ ++ INIT_POOL_BLOCK(rpool, &(rpool->first), dsize); ++ ++ return &(rpool->parent); ++} ++ ++ ++/* }}} */ ++ ++/* {{{ apc_pool_init */ ++void apc_pool_init() ++{ ++ /* put all ye sanity checks here */ ++ assert(sizeof(decaff) > REDZONE_SIZE(ALIGNWORD(sizeof(char)))); ++ assert(sizeof(pool_block) == ALIGNWORD(sizeof(pool_block))); ++#if APC_POOL_DEBUG ++ assert((APC_POOL_SIZE_MASK & (APC_POOL_SIZEINFO | APC_POOL_REDZONES)) == 0); ++#endif ++} ++/* }}} */ ++ ++/* {{{ apc_pstrdup */ ++void* APC_ALLOC apc_pstrdup(const char* s, apc_pool* pool TSRMLS_DC) ++{ ++ return s != NULL ? apc_pmemcpy(s, (strlen(s) + 1), pool TSRMLS_CC) : NULL; ++} ++/* }}} */ ++ ++/* {{{ apc_pmemcpy */ ++void* APC_ALLOC apc_pmemcpy(const void* p, size_t n, apc_pool* pool TSRMLS_DC) ++{ ++ void* q; ++ ++ if (p != NULL && (q = apc_pool_alloc(pool, n)) != NULL) { ++ memcpy(q, p, n); ++ return q; ++ } ++ return NULL; ++} ++/* }}} */ ++ ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_pool.h b/ext/apc/apc_pool.h +--- a/ext/apc/apc_pool.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_pool.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,114 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Yahoo! Inc. in 2008. ++ ++ Future revisions and derivatives of this source code must acknowledge ++ Yahoo! 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_pool.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef APC_POOL_H ++#define APC_POOL_H ++ ++#include "apc.h" ++#include "apc_sma.h" ++ ++/* #define APC_POOL_DEBUG 1 */ ++ ++typedef enum { ++ APC_UNPOOL = 0x0, ++ APC_SMALL_POOL = 0x1, ++ APC_MEDIUM_POOL = 0x2, ++ APC_LARGE_POOL = 0x3, ++ APC_POOL_SIZE_MASK = 0x7, /* waste a bit */ ++#if APC_POOL_DEBUG ++ APC_POOL_REDZONES = 0x08, ++ APC_POOL_SIZEINFO = 0x10, ++ APC_POOL_OPT_MASK = 0x18 ++#endif ++} apc_pool_type; ++ ++#if APC_POOL_DEBUG ++#define APC_POOL_HAS_SIZEINFO(pool) ((pool->type & APC_POOL_SIZEINFO)!=0) ++#define APC_POOL_HAS_REDZONES(pool) ((pool->type & APC_POOL_REDZONES)!=0) ++#else ++/* let gcc optimize away the optional features */ ++#define APC_POOL_HAS_SIZEINFO(pool) (0) ++#define APC_POOL_HAS_REDZONES(pool) (0) ++#endif ++ ++ ++typedef struct _apc_pool apc_pool; ++ ++typedef void (*apc_pcleanup_t)(apc_pool *pool TSRMLS_DC); ++ ++typedef void* (*apc_palloc_t)(apc_pool *pool, size_t size TSRMLS_DC); ++typedef void (*apc_pfree_t) (apc_pool *pool, void* p TSRMLS_DC); ++ ++typedef void* (*apc_protect_t) (void *p); ++typedef void* (*apc_unprotect_t)(void *p); ++ ++struct _apc_pool { ++ apc_pool_type type; ++ ++ apc_malloc_t allocate; ++ apc_free_t deallocate; ++ ++ apc_palloc_t palloc; ++ apc_pfree_t pfree; ++ ++ apc_protect_t protect; ++ apc_unprotect_t unprotect; ++ ++ apc_pcleanup_t cleanup; ++ ++ size_t size; ++ size_t used; ++ ++ /* apc_realpool and apc_unpool add more here */ ++}; ++ ++#define apc_pool_alloc(pool, size) ((void *) pool->palloc(pool, size TSRMLS_CC)) ++#define apc_pool_free(pool, ptr) ((void) pool->pfree (pool, ptr TSRMLS_CC)) ++ ++#define apc_pool_protect(pool, ptr) (pool->protect ? \ ++ (pool)->protect((ptr)) : (ptr)) ++ ++#define apc_pool_unprotect(pool, ptr) (pool->unprotect ? \ ++ (pool)->unprotect((ptr)) : (ptr)) ++ ++extern void apc_pool_init(); ++ ++extern apc_pool* apc_pool_create(apc_pool_type pool_type, ++ apc_malloc_t allocate, ++ apc_free_t deallocate, ++ apc_protect_t protect, ++ apc_unprotect_t unprotect ++ TSRMLS_DC); ++ ++extern void apc_pool_destroy(apc_pool* pool TSRMLS_DC); ++ ++extern void* apc_pmemcpy(const void* p, size_t n, apc_pool* pool TSRMLS_DC); ++extern void* apc_pstrdup(const char* s, apc_pool* pool TSRMLS_DC); ++ ++#endif +diff -Naur a/ext/apc/apc_pthreadmutex.c b/ext/apc/apc_pthreadmutex.c +--- a/ext/apc/apc_pthreadmutex.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_pthreadmutex.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,111 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Brian Shire | ++ +----------------------------------------------------------------------+ ++ ++ */ ++ ++/* $Id: apc_pthreadmutex.c 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#include "apc_pthreadmutex.h" ++ ++#ifdef APC_PTHREADMUTEX_LOCKS ++ ++pthread_mutex_t *apc_pthreadmutex_create(pthread_mutex_t *lock TSRMLS_DC) ++{ ++ int result; ++ pthread_mutexattr_t* attr; ++ attr = malloc(sizeof(pthread_mutexattr_t)); ++ ++ result = pthread_mutexattr_init(attr); ++ if(result == ENOMEM) { ++ apc_error("pthread mutex error: Insufficient memory exists to create the mutex attribute object." TSRMLS_CC); ++ } else if(result == EINVAL) { ++ apc_error("pthread mutex error: attr does not point to writeable memory." TSRMLS_CC); ++ } else if(result == EFAULT) { ++ apc_error("pthread mutex error: attr is an invalid pointer." TSRMLS_CC); ++ } ++ ++#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP ++ result = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ADAPTIVE_NP); ++ if (result == EINVAL) { ++ apc_error("pthread_mutexattr_settype: unable to set adaptive mutexes" TSRMLS_CC); ++ } ++#endif ++ ++ /* pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ERRORCHECK); */ ++ result = pthread_mutexattr_setpshared(attr, PTHREAD_PROCESS_SHARED); ++ if(result == EINVAL) { ++ apc_error("pthread mutex error: attr is not an initialized mutex attribute object, or pshared is not a valid process-shared state setting." TSRMLS_CC); ++ } else if(result == EFAULT) { ++ apc_error("pthread mutex error: attr is an invalid pointer." TSRMLS_CC); ++ } else if(result == ENOTSUP) { ++ apc_error("pthread mutex error: pshared was set to PTHREAD_PROCESS_SHARED." TSRMLS_CC); ++ } ++ ++ if(pthread_mutex_init(lock, attr)) { ++ apc_error("unable to initialize pthread lock" TSRMLS_CC); ++ } ++ return lock; ++} ++ ++void apc_pthreadmutex_destroy(pthread_mutex_t *lock) ++{ ++ return; /* we don't actually destroy the mutex, as it would destroy it for all processes */ ++} ++ ++void apc_pthreadmutex_lock(pthread_mutex_t *lock TSRMLS_DC) ++{ ++ int result; ++ result = pthread_mutex_lock(lock); ++ if(result == EINVAL) { ++ apc_error("unable to obtain pthread lock (EINVAL)" TSRMLS_CC); ++ } else if(result == EDEADLK) { ++ apc_error("unable to obtain pthread lock (EDEADLK)" TSRMLS_CC); ++ } ++} ++ ++void apc_pthreadmutex_unlock(pthread_mutex_t *lock TSRMLS_DC) ++{ ++ if(pthread_mutex_unlock(lock)) { ++ apc_error("unable to unlock pthread lock" TSRMLS_CC); ++ } ++} ++ ++zend_bool apc_pthreadmutex_nonblocking_lock(pthread_mutex_t *lock TSRMLS_DC) ++{ ++ int rval; ++ rval = pthread_mutex_trylock(lock); ++ if(rval == EBUSY) { /* Lock is already held */ ++ return 0; ++ } else if(rval == 0) { /* Obtained lock */ ++ return 1; ++ } else { /* Other error */ ++ apc_error("unable to obtain pthread trylock" TSRMLS_CC); ++ return 0; ++ } ++} ++ ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_pthreadmutex.h b/ext/apc/apc_pthreadmutex.h +--- a/ext/apc/apc_pthreadmutex.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_pthreadmutex.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,48 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Brian Shire | ++ +----------------------------------------------------------------------+ ++ ++ */ ++ ++/* $Id: apc_pthreadmutex.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef APC_PTHREADMUTEX_H ++#define APC_PTHREADMUTEX_H ++ ++#include "apc.h" ++ ++#ifdef APC_PTHREADMUTEX_LOCKS ++ ++#include ++ ++pthread_mutex_t *apc_pthreadmutex_create(pthread_mutex_t *lock TSRMLS_DC); ++void apc_pthreadmutex_destroy(pthread_mutex_t *lock); ++void apc_pthreadmutex_lock(pthread_mutex_t *lock TSRMLS_DC); ++void apc_pthreadmutex_unlock(pthread_mutex_t *lock TSRMLS_DC); ++zend_bool apc_pthreadmutex_nonblocking_lock(pthread_mutex_t *lock TSRMLS_DC); ++ ++#endif ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_pthreadrwlock.c b/ext/apc/apc_pthreadrwlock.c +--- a/ext/apc/apc_pthreadrwlock.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_pthreadrwlock.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,120 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Gopal V | ++ +----------------------------------------------------------------------+ ++ ++ */ ++ ++/* $Id: $ */ ++ ++#include "apc_pthreadrwlock.h" ++ ++#ifdef APC_PTHREADRW_LOCKS ++ ++pthread_rwlock_t *apc_pthreadrwlock_create(pthread_rwlock_t *lock TSRMLS_DC) ++{ ++ int result; ++ pthread_rwlockattr_t attr; ++ ++ result = pthread_rwlockattr_init(&attr); ++ if(result == ENOMEM) { ++ apc_error("pthread rwlock error: Insufficient memory exists to create the rwlock attribute object." TSRMLS_CC); ++ } else if(result == EINVAL) { ++ apc_error("pthread rwlock error: attr does not point to writeable memory." TSRMLS_CC); ++ } else if(result == EFAULT) { ++ apc_error("pthread rwlock error: attr is an invalid pointer." TSRMLS_CC); ++ } ++ ++#ifdef __USE_UNIX98 ++ pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); ++#endif ++ ++ result = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); ++ if(result == EINVAL) { ++ apc_error("pthread rwlock error: attr is not an initialized rwlock attribute object, or pshared is not a valid process-shared state setting." TSRMLS_CC); ++ } else if(result == EFAULT) { ++ apc_error("pthread rwlock error: attr is an invalid pointer." TSRMLS_CC); ++ } else if(result == ENOTSUP) { ++ apc_error("pthread rwlock error: pshared was set to PTHREAD_PROCESS_SHARED." TSRMLS_CC); ++ } ++ ++ if(pthread_rwlock_init(lock, &attr)) { ++ apc_error("unable to initialize pthread rwlock" TSRMLS_CC); ++ } ++ ++ pthread_rwlockattr_destroy(&attr); ++ ++ return lock; ++} ++ ++void apc_pthreadrwlock_destroy(pthread_rwlock_t *lock) ++{ ++ return; /* we don't actually destroy the rwlock, as it would destroy it for all processes */ ++} ++ ++void apc_pthreadrwlock_lock(pthread_rwlock_t *lock TSRMLS_DC) ++{ ++ int result; ++ result = pthread_rwlock_wrlock(lock); ++ if(result == EINVAL) { ++ apc_error("unable to obtain pthread lock (EINVAL)" TSRMLS_CC); ++ } else if(result == EDEADLK) { ++ apc_error("unable to obtain pthread lock (EDEADLK)" TSRMLS_CC); ++ } ++} ++ ++void apc_pthreadrwlock_rdlock(pthread_rwlock_t *lock TSRMLS_DC) ++{ ++ int result; ++ result = pthread_rwlock_rdlock(lock); ++ if(result == EINVAL) { ++ apc_error("unable to obtain pthread lock (EINVAL)" TSRMLS_CC); ++ } else if(result == EDEADLK) { ++ apc_error("unable to obtain pthread lock (EDEADLK)" TSRMLS_CC); ++ } ++} ++ ++void apc_pthreadrwlock_unlock(pthread_rwlock_t *lock TSRMLS_DC) ++{ ++ if(pthread_rwlock_unlock(lock)) { ++ apc_error("unable to unlock pthread lock" TSRMLS_CC); ++ } ++} ++ ++zend_bool apc_pthreadrwlock_nonblocking_lock(pthread_rwlock_t *lock TSRMLS_DC) ++{ ++ int rval; ++ rval = pthread_rwlock_trywrlock(lock); ++ if(rval == EBUSY) { /* Lock is already held */ ++ return 0; ++ } else if(rval == 0) { /* Obtained lock */ ++ return 1; ++ } else { /* Other error */ ++ apc_error("unable to obtain pthread trylock" TSRMLS_CC); ++ return 0; ++ } ++} ++ ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_pthreadrwlock.h b/ext/apc/apc_pthreadrwlock.h +--- a/ext/apc/apc_pthreadrwlock.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_pthreadrwlock.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,49 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Gopal V | ++ +----------------------------------------------------------------------+ ++ ++ */ ++ ++/* $Id: apc_pthreadrwlock.h 302175 2010-08-13 06:20:28Z kalle $ */ ++ ++#ifndef APC_PTHREADRWLOCK_H ++#define APC_PTHREADRWLOCK_H ++ ++#include "apc.h" ++ ++#ifdef APC_PTHREADRW_LOCKS ++ ++#include ++ ++pthread_rwlock_t *apc_pthreadrwlock_create(pthread_rwlock_t *lock TSRMLS_DC); ++void apc_pthreadrwlock_destroy(pthread_rwlock_t *lock); ++void apc_pthreadrwlock_lock(pthread_rwlock_t *lock TSRMLS_DC); ++void apc_pthreadrwlock_rdlock(pthread_rwlock_t *lock TSRMLS_DC); ++void apc_pthreadrwlock_unlock(pthread_rwlock_t *lock TSRMLS_DC); ++zend_bool apc_pthreadrwlock_nonblocking_lock(pthread_rwlock_t *lock TSRMLS_DC); ++ ++#endif ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_rfc1867.c b/ext/apc/apc_rfc1867.c +--- a/ext/apc/apc_rfc1867.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_rfc1867.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,236 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Community Connect Inc. in 2002 ++ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. ++ Future revisions and derivatives of this source code must acknowledge ++ Community Connect Inc. as the original contributor of this module by ++ leaving this note intact in the source code. ++ ++ All other licensing and usage conditions are those of the PHP Group. ++ ++ */ ++ ++/* $Id: apc_rfc1867.c 309694 2011-03-25 18:47:38Z rasmus $*/ ++ ++#include "apc.h" ++#include "apc_globals.h" ++#include "rfc1867.h" ++ ++#ifdef PHP_WIN32 ++#include "win32/time.h" ++#endif ++ ++#ifdef MULTIPART_EVENT_FORMDATA ++extern int _apc_store(char *strkey, int strkey_len, const zval *val, const uint ttl, const int exclusive TSRMLS_DC); ++extern int _apc_update(char *strkey, int strkey_len, apc_cache_updater_t updater, void* data TSRMLS_DC); ++ ++static int update_bytes_processed(apc_cache_t* cache, apc_cache_entry_t* entry, void* data) { ++ int *bytes_ptr = (int*)data; ++ zval* val = entry->data.user.val; ++ ++ if(Z_TYPE_P(val) == IS_ARRAY) { ++ HashTable *ht = val->value.ht; ++ Bucket* curr = NULL; ++ for (curr = ht->pListHead; curr != NULL; curr = curr->pListNext) { ++ if(curr->nKeyLength == 8 && ++ (!memcmp(curr->arKey, "current", curr->nKeyLength))) { ++ zval* current = ((zval**)curr->pData)[0]; ++ current->value.lval = *bytes_ptr; ++ return 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static double my_time() { ++ struct timeval a; ++ double t; ++ gettimeofday(&a, NULL); ++ t = a.tv_sec + (a.tv_usec/1000000.00); ++ return t; ++} ++ ++ ++#define RFC1867_DATA(name) \ ++ ((request_data)->name) ++ ++int apc_rfc1867_progress(uint event, void *event_data, void **extra TSRMLS_DC) { ++ apc_rfc1867_data *request_data = &APCG(rfc1867_data); ++ zval *track = NULL; ++ ++ switch (event) { ++ case MULTIPART_EVENT_START: ++ { ++ multipart_event_start *data = (multipart_event_start *) event_data; ++ ++ RFC1867_DATA(content_length) = data->content_length; ++ RFC1867_DATA(tracking_key)[0] = '\0'; ++ RFC1867_DATA(name)[0] = '\0'; ++ RFC1867_DATA(cancel_upload) = 0; ++ RFC1867_DATA(temp_filename) = NULL; ++ RFC1867_DATA(filename)[0] = '\0'; ++ RFC1867_DATA(key_length) = 0; ++ RFC1867_DATA(start_time) = my_time(); ++ RFC1867_DATA(bytes_processed) = 0; ++ RFC1867_DATA(prev_bytes_processed) = 0; ++ RFC1867_DATA(rate) = 0; ++ RFC1867_DATA(update_freq) = (int) APCG(rfc1867_freq); ++ RFC1867_DATA(started) = 0; ++ ++ if(RFC1867_DATA(update_freq) < 0) { // frequency is a percentage, not bytes ++ RFC1867_DATA(update_freq) = (int) (RFC1867_DATA(content_length) * APCG(rfc1867_freq) / 100); ++ } ++ } ++ break; ++ ++ case MULTIPART_EVENT_FORMDATA: ++ { ++ int prefix_len = strlen(APCG(rfc1867_prefix)); ++ multipart_event_formdata *data = (multipart_event_formdata *) event_data; ++ if(data->name && !strncasecmp(data->name, APCG(rfc1867_name), strlen(APCG(rfc1867_name))) ++ && data->value && data->length) { ++ ++ if(data->length >= sizeof(RFC1867_DATA(tracking_key)) - prefix_len) { ++ apc_warning("Key too long for '%s'. Maximum size is '%d' characters." TSRMLS_CC, ++ APCG(rfc1867_name), ++ sizeof(RFC1867_DATA(tracking_key)) - prefix_len); ++ break; ++ } ++ ++ if(RFC1867_DATA(started)) { ++ apc_warning("Upload progress key '%s' should be before the file upload entry in the form." TSRMLS_CC, ++ APCG(rfc1867_name)); ++ break; ++ } ++ ++ strlcat(RFC1867_DATA(tracking_key), APCG(rfc1867_prefix), 63); ++ strlcat(RFC1867_DATA(tracking_key), *data->value, 63); ++ RFC1867_DATA(key_length) = data->length + prefix_len; ++ RFC1867_DATA(bytes_processed) = data->post_bytes_processed; ++ } ++ } ++ break; ++ ++ case MULTIPART_EVENT_FILE_START: ++ { ++ RFC1867_DATA(started) = 1; ++ if(*RFC1867_DATA(tracking_key)) { ++ multipart_event_file_start *data = (multipart_event_file_start *) event_data; ++ ++ RFC1867_DATA(bytes_processed) = data->post_bytes_processed; ++ strlcpy(RFC1867_DATA(filename),*data->filename,128); ++ RFC1867_DATA(temp_filename) = NULL; ++ strlcpy(RFC1867_DATA(name),data->name,64); ++ ALLOC_INIT_ZVAL(track); ++ array_init(track); ++ add_assoc_long(track, "total", RFC1867_DATA(content_length)); ++ add_assoc_long(track, "current", RFC1867_DATA(bytes_processed)); ++ add_assoc_string(track, "filename", RFC1867_DATA(filename), 1); ++ add_assoc_string(track, "name", RFC1867_DATA(name), 1); ++ add_assoc_long(track, "done", 0); ++ add_assoc_double(track, "start_time", RFC1867_DATA(start_time)); ++ _apc_store(RFC1867_DATA(tracking_key), RFC1867_DATA(key_length)+1, track, APCG(rfc1867_ttl), 0 TSRMLS_CC); ++ zval_ptr_dtor(&track); ++ } ++ } ++ break; ++ ++ case MULTIPART_EVENT_FILE_DATA: ++ if(*RFC1867_DATA(tracking_key)) { ++ multipart_event_file_data *data = (multipart_event_file_data *) event_data; ++ RFC1867_DATA(bytes_processed) = data->post_bytes_processed; ++ if(RFC1867_DATA(bytes_processed) - RFC1867_DATA(prev_bytes_processed) > (uint) RFC1867_DATA(update_freq)) { ++ if(!_apc_update(RFC1867_DATA(tracking_key), RFC1867_DATA(key_length), update_bytes_processed, &RFC1867_DATA(bytes_processed) TSRMLS_CC)) { ++ ALLOC_INIT_ZVAL(track); ++ array_init(track); ++ add_assoc_long(track, "total", RFC1867_DATA(content_length)); ++ add_assoc_long(track, "current", RFC1867_DATA(bytes_processed)); ++ add_assoc_string(track, "filename", RFC1867_DATA(filename), 1); ++ add_assoc_string(track, "name", RFC1867_DATA(name), 1); ++ add_assoc_long(track, "done", 0); ++ add_assoc_double(track, "start_time", RFC1867_DATA(start_time)); ++ _apc_store(RFC1867_DATA(tracking_key), RFC1867_DATA(key_length)+1, track, APCG(rfc1867_ttl), 0 TSRMLS_CC); ++ zval_ptr_dtor(&track); ++ } ++ RFC1867_DATA(prev_bytes_processed) = RFC1867_DATA(bytes_processed); ++ } ++ } ++ break; ++ ++ case MULTIPART_EVENT_FILE_END: ++ if(*RFC1867_DATA(tracking_key)) { ++ multipart_event_file_end *data = (multipart_event_file_end *) event_data; ++ RFC1867_DATA(bytes_processed) = data->post_bytes_processed; ++ RFC1867_DATA(cancel_upload) = data->cancel_upload; ++ if(data->temp_filename) { ++ RFC1867_DATA(temp_filename) = data->temp_filename; ++ } else { ++ RFC1867_DATA(temp_filename) = ""; ++ } ++ ALLOC_INIT_ZVAL(track); ++ array_init(track); ++ add_assoc_long(track, "total", RFC1867_DATA(content_length)); ++ add_assoc_long(track, "current", RFC1867_DATA(bytes_processed)); ++ add_assoc_string(track, "filename", RFC1867_DATA(filename), 1); ++ add_assoc_string(track, "name", RFC1867_DATA(name), 1); ++ add_assoc_string(track, "temp_filename", RFC1867_DATA(temp_filename), 1); ++ add_assoc_long(track, "cancel_upload", RFC1867_DATA(cancel_upload)); ++ add_assoc_long(track, "done", 0); ++ add_assoc_double(track, "start_time", RFC1867_DATA(start_time)); ++ _apc_store(RFC1867_DATA(tracking_key), RFC1867_DATA(key_length)+1, track, APCG(rfc1867_ttl), 0 TSRMLS_CC); ++ zval_ptr_dtor(&track); ++ } ++ break; ++ ++ case MULTIPART_EVENT_END: ++ if(*RFC1867_DATA(tracking_key)) { ++ double now = my_time(); ++ multipart_event_end *data = (multipart_event_end *) event_data; ++ RFC1867_DATA(bytes_processed) = data->post_bytes_processed; ++ if(now>RFC1867_DATA(start_time)) RFC1867_DATA(rate) = 8.0*RFC1867_DATA(bytes_processed)/(now-RFC1867_DATA(start_time)); ++ else RFC1867_DATA(rate) = 8.0*RFC1867_DATA(bytes_processed); /* Too quick */ ++ ALLOC_INIT_ZVAL(track); ++ array_init(track); ++ add_assoc_long(track, "total", RFC1867_DATA(content_length)); ++ add_assoc_long(track, "current", RFC1867_DATA(bytes_processed)); ++ add_assoc_double(track, "rate", RFC1867_DATA(rate)); ++ add_assoc_string(track, "filename", RFC1867_DATA(filename), 1); ++ add_assoc_string(track, "name", RFC1867_DATA(name), 1); ++ add_assoc_long(track, "cancel_upload", RFC1867_DATA(cancel_upload)); ++ add_assoc_long(track, "done", 1); ++ add_assoc_double(track, "start_time", RFC1867_DATA(start_time)); ++ _apc_store(RFC1867_DATA(tracking_key), RFC1867_DATA(key_length)+1, track, APCG(rfc1867_ttl), 0 TSRMLS_CC); ++ zval_ptr_dtor(&track); ++ } ++ break; ++ } ++ ++ return SUCCESS; ++} ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_sem.c b/ext/apc/apc_sem.c +--- a/ext/apc/apc_sem.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_sem.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,192 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ +----------------------------------------------------------------------+ ++ ++ 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_sem.c 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#include "apc.h" ++ ++#ifdef APC_SEM_LOCKS ++ ++#include "apc_sem.h" ++#include "php.h" ++#include ++#include ++#include ++#include ++#include ++ ++#if HAVE_SEMUN ++/* we have semun, no need to define */ ++#else ++#undef HAVE_SEMUN ++union semun { ++ int val; /* value for SETVAL */ ++ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ ++ unsigned short *array; /* array for GETALL, SETALL */ ++ /* Linux specific part: */ ++ struct seminfo *__buf; /* buffer for IPC_INFO */ ++}; ++#define HAVE_SEMUN 1 ++#endif ++ ++#ifndef SEM_R ++# define SEM_R 0444 ++#endif ++#ifndef SEM_A ++# define SEM_A 0222 ++#endif ++ ++/* always use SEM_UNDO, otherwise we risk deadlock */ ++#define USE_SEM_UNDO ++ ++#ifdef USE_SEM_UNDO ++# define UNDO SEM_UNDO ++#else ++# define UNDO 0 ++#endif ++ ++int apc_sem_create(int proj, int initval TSRMLS_DC) ++{ ++ int semid; ++ int perms = 0777; ++ union semun arg; ++ key_t key = IPC_PRIVATE; ++ ++ if ((semid = semget(key, 1, IPC_CREAT | IPC_EXCL | perms)) >= 0) { ++ /* sempahore created for the first time, initialize now */ ++ arg.val = initval; ++ if (semctl(semid, 0, SETVAL, arg) < 0) { ++ apc_error("apc_sem_create: semctl(%d,...) failed:" TSRMLS_CC, semid); ++ } ++ } ++ else if (errno == EEXIST) { ++ /* sempahore already exists, don't initialize */ ++ if ((semid = semget(key, 1, perms)) < 0) { ++ apc_error("apc_sem_create: semget(%u,...) failed:" TSRMLS_CC, key); ++ } ++ /* insert here */ ++ } ++ else { ++ apc_error("apc_sem_create: semget(%u,...) failed:" TSRMLS_CC, key); ++ } ++ ++ return semid; ++} ++ ++void apc_sem_destroy(int semid) ++{ ++ /* we expect this call to fail often, so we do not check */ ++ union semun arg; ++ semctl(semid, 0, IPC_RMID, arg); ++} ++ ++void apc_sem_lock(int semid TSRMLS_DC) ++{ ++ struct sembuf op; ++ ++ op.sem_num = 0; ++ op.sem_op = -1; ++ op.sem_flg = UNDO; ++ ++ if (semop(semid, &op, 1) < 0) { ++ if (errno != EINTR) { ++ apc_error("apc_sem_lock: semop(%d) failed:" TSRMLS_CC, semid); ++ } ++ } ++} ++ ++int apc_sem_nonblocking_lock(int semid TSRMLS_DC) ++{ ++ struct sembuf op; ++ ++ op.sem_num = 0; ++ op.sem_op = -1; ++ op.sem_flg = UNDO | IPC_NOWAIT; ++ ++ if (semop(semid, &op, 1) < 0) { ++ if (errno == EAGAIN) { ++ return 0; /* Lock is already held */ ++ } else if (errno != EINTR) { ++ apc_error("apc_sem_lock: semop(%d) failed:" TSRMLS_CC, semid); ++ } ++ } ++ ++ return 1; /* Lock obtained */ ++} ++ ++void apc_sem_unlock(int semid TSRMLS_DC) ++{ ++ struct sembuf op; ++ ++ op.sem_num = 0; ++ op.sem_op = 1; ++ op.sem_flg = UNDO; ++ ++ if (semop(semid, &op, 1) < 0) { ++ if (errno != EINTR) { ++ apc_error("apc_sem_unlock: semop(%d) failed:" TSRMLS_CC, semid); ++ } ++ } ++} ++ ++void apc_sem_wait_for_zero(int semid TSRMLS_DC) ++{ ++ struct sembuf op; ++ ++ op.sem_num = 0; ++ op.sem_op = 0; ++ op.sem_flg = UNDO; ++ ++ if (semop(semid, &op, 1) < 0) { ++ if (errno != EINTR) { ++ apc_error("apc_sem_waitforzero: semop(%d) failed:" TSRMLS_CC, semid); ++ } ++ } ++} ++ ++int apc_sem_get_value(int semid TSRMLS_DC) ++{ ++ union semun arg; ++ unsigned short val[1]; ++ ++ arg.array = val; ++ if (semctl(semid, 0, GETALL, arg) < 0) { ++ apc_error("apc_sem_getvalue: semctl(%d,...) failed:" TSRMLS_CC, semid); ++ } ++ return val[0]; ++} ++ ++#endif /* APC_SEM_LOCKS */ ++ ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_sem.h b/ext/apc/apc_sem.h +--- a/ext/apc/apc_sem.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_sem.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,52 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ +----------------------------------------------------------------------+ ++ ++ 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_sem.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef APC_SEM_H ++#define APC_SEM_H ++ ++/* Wrapper functions for SysV sempahores */ ++ ++extern int apc_sem_create(int proj, int initval TSRMLS_DC); ++extern void apc_sem_destroy(int semid); ++extern void apc_sem_lock(int semid TSRMLS_DC); ++extern int apc_sem_nonblocking_lock(int semid TSRMLS_DC); ++extern void apc_sem_unlock(int semid TSRMLS_DC); ++extern void apc_sem_wait_for_zero(int semid TSRMLS_DC); ++extern int apc_sem_get_value(int semid TSRMLS_DC); ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_serializer.h b/ext/apc/apc_serializer.h +--- a/ext/apc/apc_serializer.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_serializer.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,84 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Gopal Vijayaraghavan | ++ +----------------------------------------------------------------------+ ++ ++ */ ++ ++/* $Id: $ */ ++ ++#ifndef APC_SERIALIZER_H ++#define APC_SERIALIZER_H ++ ++/* this is a shipped .h file, do not include any other header in this file */ ++#define APC_SERIALIZER_NAME(module) module##_apc_serializer ++#define APC_UNSERIALIZER_NAME(module) module##_apc_unserializer ++ ++#define APC_SERIALIZER_ARGS unsigned char **buf, size_t *buf_len, const zval *value, void *config TSRMLS_DC ++#define APC_UNSERIALIZER_ARGS zval **value, unsigned char *buf, size_t buf_len, void *config TSRMLS_DC ++ ++typedef int (*apc_serialize_t)(APC_SERIALIZER_ARGS); ++typedef int (*apc_unserialize_t)(APC_UNSERIALIZER_ARGS); ++ ++typedef int (*apc_register_serializer_t)(const char* name, ++ apc_serialize_t serialize, ++ apc_unserialize_t unserialize, ++ void *config TSRMLS_DC); ++ ++/* ++ * ABI version for constant hooks. Increment this any time you make any changes ++ * to any function in this file. ++ */ ++#define APC_SERIALIZER_ABI "0" ++#define APC_SERIALIZER_CONSTANT "\000apc_register_serializer-" APC_SERIALIZER_ABI ++ ++#if !defined(APC_UNUSED) ++# if defined(__GNUC__) ++# define APC_UNUSED __attribute__((unused)) ++# else ++# define APC_UNUSED ++# endif ++#endif ++ ++static APC_UNUSED int apc_register_serializer(const char* name, ++ apc_serialize_t serialize, ++ apc_unserialize_t unserialize, ++ void *config TSRMLS_DC) ++{ ++ zval apc_magic_constant; ++ int retval = 0; ++ ++ /* zend_get_constant will return 1 on success, otherwise apc_magic_constant wouldn't be touched at all */ ++ if (zend_get_constant(APC_SERIALIZER_CONSTANT, sizeof(APC_SERIALIZER_CONSTANT)-1, &apc_magic_constant TSRMLS_CC)) { ++ apc_register_serializer_t register_func = (apc_register_serializer_t)(Z_LVAL(apc_magic_constant)); ++ if(register_func) { ++ retval = register_func(name, serialize, unserialize, NULL TSRMLS_CC); ++ } ++ zval_dtor(&apc_magic_constant); ++ } ++ ++ return retval; ++} ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_shm.c b/ext/apc/apc_shm.c +--- a/ext/apc/apc_shm.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_shm.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,116 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Community Connect Inc. in 2002 ++ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. ++ Future revisions and derivatives of this source code must acknowledge ++ Community Connect Inc. as the original contributor of this module by ++ leaving this note intact in the source code. ++ ++ All other licensing and usage conditions are those of the PHP Group. ++ ++ */ ++ ++/* $Id: apc_shm.c 307259 2011-01-08 12:05:24Z gopalv $ */ ++ ++#include "apc_shm.h" ++#include "apc.h" ++#ifdef PHP_WIN32 ++/* shm functions are available in TSRM */ ++#include ++#define key_t long ++#else ++#include ++#include ++#include ++#endif ++ ++#ifndef SHM_R ++# define SHM_R 0444 /* read permission */ ++#endif ++#ifndef SHM_A ++# define SHM_A 0222 /* write permission */ ++#endif ++ ++int apc_shm_create(int proj, size_t size TSRMLS_DC) ++{ ++ int shmid; /* shared memory id */ ++ int oflag; /* permissions on shm */ ++ key_t key = IPC_PRIVATE; /* shm key */ ++ ++ oflag = IPC_CREAT | SHM_R | SHM_A; ++ if ((shmid = shmget(key, size, oflag)) < 0) { ++ apc_error("apc_shm_create: shmget(%d, %d, %d) failed: %s. It is possible that the chosen SHM segment size is higher than the operation system allows. Linux has usually a default limit of 32MB per segment." TSRMLS_CC, key, size, oflag, strerror(errno)); ++ } ++ ++ return shmid; ++} ++ ++void apc_shm_destroy(int shmid) ++{ ++ /* we expect this call to fail often, so we do not check */ ++ shmctl(shmid, IPC_RMID, 0); ++} ++ ++apc_segment_t apc_shm_attach(int shmid, size_t size TSRMLS_DC) ++{ ++ apc_segment_t segment; /* shm segment */ ++ ++ if ((long)(segment.shmaddr = shmat(shmid, 0, 0)) == -1) { ++ apc_error("apc_shm_attach: shmat failed:" TSRMLS_CC); ++ } ++ ++#ifdef APC_MEMPROTECT ++ ++ if ((long)(segment.roaddr = shmat(shmid, 0, SHM_RDONLY)) == -1) { ++ segment.roaddr = NULL; ++ } ++ ++#endif ++ ++ segment.size = size; ++ ++ /* ++ * We set the shmid for removal immediately after attaching to it. The ++ * segment won't disappear until all processes have detached from it. ++ */ ++ apc_shm_destroy(shmid); ++ return segment; ++} ++ ++void apc_shm_detach(apc_segment_t* segment TSRMLS_DC) ++{ ++ if (shmdt(segment->shmaddr) < 0) { ++ apc_error("apc_shm_detach: shmdt failed:" TSRMLS_CC); ++ } ++ ++#ifdef APC_MEMPROTECT ++ if (segment->roaddr && shmdt(segment->roaddr) < 0) { ++ apc_error("apc_shm_detach: shmdt failed:" TSRMLS_CC); ++ } ++#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 ++ */ +diff -Naur a/ext/apc/apc_shm.h b/ext/apc/apc_shm.h +--- a/ext/apc/apc_shm.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_shm.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,56 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ +----------------------------------------------------------------------+ ++ ++ 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_shm.h 307259 2011-01-08 12:05:24Z gopalv $ */ ++ ++#ifndef APC_SHM_H ++#define APC_SHM_H ++ ++#include ++#ifdef PHP_WIN32 ++#include ++#endif ++ ++#include "apc_sma.h" ++ ++/* Wrapper functions for unix shared memory */ ++ ++extern int apc_shm_create(int proj, size_t size TSRMLS_DC); ++extern void apc_shm_destroy(int shmid); ++extern apc_segment_t apc_shm_attach(int shmid, size_t size TSRMLS_DC); ++extern void apc_shm_detach(apc_segment_t* segment TSRMLS_DC); ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_signal.c b/ext/apc/apc_signal.c +--- a/ext/apc/apc_signal.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_signal.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,197 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Lucas Nealan | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Facebook Inc. in 2007. ++ ++ Future revisions and derivatives of this source code must acknowledge ++ Facebook 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_signal.c 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++ /* Allows apc to install signal handlers and maintain signalling ++ to already registered handlers. Registers all signals that ++ coredump by default and unmaps the shared memory segment ++ before the coredump. Note: PHP module init is called before ++ signals are set by Apache and thus apc_set_signals should ++ be called in request init (RINIT) ++ */ ++ ++#include "apc.h" ++ ++#if HAVE_SIGACTION ++#include ++#include "apc_globals.h" ++#include "apc_sma.h" ++#include "apc_signal.h" ++ ++static apc_signal_info_t apc_signal_info = {0}; ++ ++static int apc_register_signal(int signo, void (*handler)(int, siginfo_t*, void*) TSRMLS_DC); ++static void apc_rehandle_signal(int signo, siginfo_t *siginfo, void *context); ++static void apc_core_unmap(int signo, siginfo_t *siginfo, void *context); ++ ++/* {{{ apc_core_unmap ++ * Coredump signal handler, unmaps shm and calls previously installed handlers ++ */ ++static void apc_core_unmap(int signo, siginfo_t *siginfo, void *context) ++{ ++ TSRMLS_FETCH(); + -+ if ($freeseg > 1) { -+ $frag = sprintf("%.2f%% (%s out of %s in %d fragments)", ($fragsize/$freetotal)*100,bsize($fragsize),bsize($freetotal),$freeseg); -+ } else { -+ $frag = "0%"; -+ } ++ apc_sma_cleanup(TSRMLS_C); ++ apc_rehandle_signal(signo, siginfo, context); ++ ++#if !defined(WIN32) && !defined(NETWARE) ++ kill(getpid(), signo); ++#else ++ raise(signo); ++#endif ++} /* }}} */ ++ ++/* {{{ apc_rehandle_signal ++ * Call the previously registered handler for a signal ++ */ ++static void apc_rehandle_signal(int signo, siginfo_t *siginfo, void *context) ++{ ++ int i; ++ apc_signal_entry_t p_sig = {0}; ++ ++ for (i=0; (i < apc_signal_info.installed && p_sig.signo != signo); i++) { ++ p_sig = *apc_signal_info.prev[i]; ++ if (p_sig.signo == signo) { ++ if (p_sig.siginfo) { ++ (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context); ++ } else { ++ (*(void (*)(int))p_sig.handler)(signo); ++ } ++ } ++ } ++ ++} /* }}} */ ++ ++/* {{{ apc_register_signal ++ * Set a handler for a previously installed signal and save so we can ++ * callback when handled ++ */ ++static int apc_register_signal(int signo, void (*handler)(int, siginfo_t*, void*) TSRMLS_DC) ++{ ++ struct sigaction sa = {{0}}; ++ apc_signal_entry_t p_sig = {0}; ++ ++ if (sigaction(signo, NULL, &sa) == 0) { ++ if ((void*)sa.sa_handler == (void*)handler) { ++ return SUCCESS; ++ } ++ ++ if (sa.sa_handler != SIG_ERR && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) { ++ p_sig.signo = signo; ++ p_sig.siginfo = ((sa.sa_flags & SA_SIGINFO) == SA_SIGINFO); ++ p_sig.handler = (void *)sa.sa_handler; ++ ++ apc_signal_info.prev = (apc_signal_entry_t **)apc_erealloc(apc_signal_info.prev, (apc_signal_info.installed+1)*sizeof(apc_signal_entry_t *) TSRMLS_CC); ++ apc_signal_info.prev[apc_signal_info.installed] = (apc_signal_entry_t *)apc_emalloc(sizeof(apc_signal_entry_t) TSRMLS_CC); ++ *apc_signal_info.prev[apc_signal_info.installed++] = p_sig; ++ } else { ++ /* inherit flags and mask if already set */ ++ sigemptyset(&sa.sa_mask); ++ sa.sa_flags = 0; ++ sa.sa_flags |= SA_SIGINFO; /* we'll use a siginfo handler */ ++#if defined(SA_ONESHOT) ++ sa.sa_flags = SA_ONESHOT; ++#elif defined(SA_RESETHAND) ++ sa.sa_flags = SA_RESETHAND; ++#endif ++ } ++ sa.sa_handler = (void*)handler; ++ ++ if (sigaction(signo, &sa, NULL) < 0) { ++ apc_warning("Error installing apc signal handler for %d" TSRMLS_CC, signo); ++ } ++ ++ return SUCCESS; ++ } ++ return FAILURE; ++} /* }}} */ ++ ++/* {{{ apc_set_signals ++ * Install our signal handlers */ ++void apc_set_signals(TSRMLS_D) ++{ ++ if (APCG(coredump_unmap) && apc_signal_info.installed == 0) { ++ /* ISO C standard signals that coredump */ ++ apc_register_signal(SIGSEGV, apc_core_unmap TSRMLS_CC); ++ apc_register_signal(SIGABRT, apc_core_unmap TSRMLS_CC); ++ apc_register_signal(SIGFPE, apc_core_unmap TSRMLS_CC); ++ apc_register_signal(SIGILL, apc_core_unmap TSRMLS_CC); ++ /* extended signals that coredump */ ++#ifdef SIGBUS ++ apc_register_signal(SIGBUS, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGABORT ++ apc_register_signal(SIGABORT, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGEMT ++ apc_register_signal(SIGEMT, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGIOT ++ apc_register_signal(SIGIOT, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGQUIT ++ apc_register_signal(SIGQUIT, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGSYS ++ apc_register_signal(SIGSYS, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGTRAP ++ apc_register_signal(SIGTRAP, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGXCPU ++ apc_register_signal(SIGXCPU, apc_core_unmap TSRMLS_CC); ++#endif ++#ifdef SIGXFSZ ++ apc_register_signal(SIGXFSZ, apc_core_unmap TSRMLS_CC); ++#endif ++ } ++} /* }}} */ ++ ++/* {{{ apc_set_signals ++ * cleanup signals for shutdown */ ++void apc_shutdown_signals(TSRMLS_D) ++{ ++ int i=0; ++ if (apc_signal_info.installed > 0) { ++ for (i=0; (i < apc_signal_info.installed); i++) { ++ apc_efree(apc_signal_info.prev[i] TSRMLS_CC); ++ } ++ apc_efree(apc_signal_info.prev TSRMLS_CC); ++ apc_signal_info.installed = 0; /* just in case */ ++ } ++} ++ ++#endif /* HAVE_SIGACTION */ ++ ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_signal.h b/ext/apc/apc_signal.h +--- a/ext/apc/apc_signal.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_signal.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,51 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Lucas Nealan | ++ +----------------------------------------------------------------------+ ++ ++ */ ++ ++/* $Id: apc_signal.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef APC_SIGNAL_H ++#define APC_SIGNAL_H ++ ++#include "apc.h" ++#include "apc_php.h" ++ ++typedef struct apc_signal_entry_t { ++ int signo; /* signal number */ ++ int siginfo; /* siginfo style handler calling */ ++ void* handler; /* signal handler */ ++} apc_signal_entry_t; ++ ++typedef struct apc_signal_info_t { ++ int installed; /* How many signals we've installed handles for */ ++ apc_signal_entry_t **prev; /* Previous signal handlers */ ++} apc_signal_info_t; ++ ++void apc_set_signals(TSRMLS_D); ++void apc_shutdown_signals(TSRMLS_D); ++ ++#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 ++ */ +diff -Naur a/ext/apc/apc_sma.c b/ext/apc/apc_sma.c +--- a/ext/apc/apc_sma.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_sma.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,765 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Community Connect Inc. in 2002 ++ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. ++ Future revisions and derivatives of this source code must acknowledge ++ Community Connect Inc. as the original contributor of this module by ++ leaving this note intact in the source code. ++ ++ All other licensing and usage conditions are those of the PHP Group. ++ ++ */ ++ ++/* $Id: apc_sma.c 309489 2011-03-21 00:00:54Z pajoye $ */ ++ ++#include "apc_sma.h" ++#include "apc.h" ++#include "apc_globals.h" ++#include "apc_lock.h" ++#include "apc_shm.h" ++#include "apc_cache.h" ++ ++#include ++#include "apc_mmap.h" ++ ++#ifdef HAVE_VALGRIND_MEMCHECK_H ++#include ++#endif ++ ++enum { DEFAULT_NUMSEG=1, DEFAULT_SEGSIZE=30*1024*1024 }; ++ ++static int sma_initialized = 0; /* true if the sma has been initialized */ ++static uint sma_numseg; /* number of shm segments to allow */ ++static size_t sma_segsize; /* size of each shm segment */ ++static apc_segment_t* sma_segments; /* array of shm segments */ ++static int sma_lastseg = 0; /* index of MRU segment */ ++ ++typedef struct sma_header_t sma_header_t; ++struct sma_header_t { ++ apc_lck_t sma_lock; /* segment lock, MUST BE ALIGNED for futex locks */ ++ size_t segsize; /* size of entire segment */ ++ size_t avail; /* bytes available (not necessarily contiguous) */ ++#if ALLOC_DISTRIBUTION ++ size_t adist[30]; ++#endif ++}; ++ ++#define SMA_HDR(i) ((sma_header_t*)((sma_segments[i]).shmaddr)) ++#define SMA_ADDR(i) ((char*)(SMA_HDR(i))) ++#define SMA_RO(i) ((char*)(sma_segments[i]).roaddr) ++#define SMA_LCK(i) ((SMA_HDR(i))->sma_lock) ++ ++ ++/* do not enable for threaded http servers */ ++/* #define __APC_SMA_DEBUG__ 1 */ ++ ++#ifdef __APC_SMA_DEBUG__ ++/* global counter for identifying blocks ++ * Technically it is possible to do the same ++ * using offsets, but double allocations of the ++ * same offset can happen. */ ++static volatile size_t block_id = 0; ++#endif ++ ++#define APC_SMA_CANARIES 1 ++ ++typedef struct block_t block_t; ++struct block_t { ++ size_t size; /* size of this block */ ++ size_t prev_size; /* size of sequentially previous block, 0 if prev is allocated */ ++ size_t fnext; /* offset in segment of next free block */ ++ size_t fprev; /* offset in segment of prev free block */ ++#ifdef APC_SMA_CANARIES ++ size_t canary; /* canary to check for memory overwrites */ ++#endif ++#ifdef __APC_SMA_DEBUG__ ++ size_t id; /* identifier for the memory block */ ++#endif ++}; ++ ++/* The macros BLOCKAT and OFFSET are used for convenience throughout this ++ * module. Both assume the presence of a variable shmaddr that points to the ++ * beginning of the shared memory segment in question. */ ++ ++#define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset)) ++#define OFFSET(block) ((size_t)(((char*)block) - (char*)shmaddr)) ++ ++/* macros for getting the next or previous sequential block */ ++#define NEXT_SBLOCK(block) ((block_t*)((char*)block + block->size)) ++#define PREV_SBLOCK(block) (block->prev_size ? ((block_t*)((char*)block - block->prev_size)) : NULL) ++ ++/* Canary macros for setting, checking and resetting memory canaries */ ++#ifdef APC_SMA_CANARIES ++ #define SET_CANARY(v) (v)->canary = 0x42424242 ++ #define CHECK_CANARY(v) assert((v)->canary == 0x42424242) ++ #define RESET_CANARY(v) (v)->canary = -42 ++#else ++ #define SET_CANARY(v) ++ #define CHECK_CANARY(v) ++ #define RESET_CANARY(v) ++#endif ++ ++ ++/* {{{ MINBLOCKSIZE */ ++#define MINBLOCKSIZE (ALIGNWORD(1) + ALIGNWORD(sizeof(block_t))) ++/* }}} */ ++ ++#if 0 ++/* {{{ sma_debug_state(apc_sma_segment_t *segment, int canary_check, int verbose) ++ * useful for debuging state of memory blocks and free list, and sanity checking ++ */ ++static void sma_debug_state(void* shmaddr, int canary_check, int verbose TSRMLS_DC) { ++ sma_header_t *header = (sma_header_t*)shmaddr; ++ block_t *cur = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); ++ block_t *prv = NULL; ++ size_t avail; ++ ++ /* Verify free list */ ++ if (verbose) apc_warning("Free List: " TSRMLS_CC); ++ while(1) { ++ if (verbose) apc_warning(" 0x%x[%d] (s%d)" TSRMLS_CC, cur, OFFSET(cur), cur->size); ++ if (canary_check) CHECK_CANARY(cur); ++ if (!cur->fnext) break; ++ cur = BLOCKAT(cur->fnext); ++ avail += cur->size; ++ if (prv == cur) { ++ apc_warning("Circular list detected!" TSRMLS_CC); ++ assert(0); ++ } ++ if (prv && cur->fprev != OFFSET(prv)) { ++ apc_warning("Previous pointer does not point to previous!" TSRMLS_CC); ++ assert(0); ++ } ++ prv = cur; ++ } ++ assert(avail == header->avail); ++ ++ /* Verify each block */ ++ if (verbose) apc_warning("Block List: " TSRMLS_CC); ++ cur = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); ++ while(1) { ++ if(!cur->fnext) { ++ if (verbose) apc_warning(" 0x%x[%d] (s%d) (u)" TSRMLS_CC, cur, OFFSET(cur), cur->size); ++ } else { ++ if (verbose) apc_warning(" 0x%x[%d] (s%d) (f)" TSRMLS_CC, cur, OFFSET(cur), cur->size); ++ } ++ if (canary_check) CHECK_CANARY(cur); ++ if (!cur->size && !cur->fnext) break; ++ if (!cur->size) { ++ cur = BLOCKAT(OFFSET(cur) + ALIGNWORD(sizeof(block_t))); ++ } else { ++ cur = NEXT_SBLOCK(cur); ++ } ++ if (prv == cur) { ++ apc_warning("Circular list detected!" TSRMLS_CC); ++ assert(0); ++ } ++ prv = cur; ++ } ++} ++/* }}} */ ++#endif ++ ++/* {{{ sma_allocate: tries to allocate at least size bytes in a segment */ ++static APC_HOTSPOT size_t sma_allocate(sma_header_t* header, size_t size, size_t fragment, size_t *allocated) ++{ ++ void* shmaddr; /* header of shared memory segment */ ++ block_t* prv; /* block prior to working block */ ++ block_t* cur; /* working block in list */ ++ block_t* prvnextfit; /* block before next fit */ ++ size_t realsize; /* actual size of block needed, including header */ ++ const size_t block_size = ALIGNWORD(sizeof(struct block_t)); ++ ++ realsize = ALIGNWORD(size + block_size); ++ ++ /* ++ * First, insure that the segment contains at least realsize free bytes, ++ * even if they are not contiguous. ++ */ ++ shmaddr = header; ++ ++ if (header->avail < realsize) { ++ return -1; ++ } ++ ++ prvnextfit = 0; /* initially null (no fit) */ ++ prv = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); ++ CHECK_CANARY(prv); ++ ++ while (prv->fnext != 0) { ++ cur = BLOCKAT(prv->fnext); ++#ifdef __APC_SMA_DEBUG__ ++ CHECK_CANARY(cur); ++#endif ++ /* If it can fit realsize bytes in cur block, stop searching */ ++ if (cur->size >= realsize) { ++ prvnextfit = prv; ++ break; ++ } ++ prv = cur; ++ } ++ ++ if (prvnextfit == 0) { ++ return -1; ++ } ++ ++ prv = prvnextfit; ++ cur = BLOCKAT(prv->fnext); ++ ++ CHECK_CANARY(prv); ++ CHECK_CANARY(cur); ++ ++ if (cur->size == realsize || (cur->size > realsize && cur->size < (realsize + (MINBLOCKSIZE + fragment)))) { ++ /* cur is big enough for realsize, but too small to split - unlink it */ ++ *(allocated) = cur->size - block_size; ++ prv->fnext = cur->fnext; ++ BLOCKAT(cur->fnext)->fprev = OFFSET(prv); ++ NEXT_SBLOCK(cur)->prev_size = 0; /* block is alloc'd */ ++ } else { ++ /* nextfit is too big; split it into two smaller blocks */ ++ block_t* nxt; /* the new block (chopped part of cur) */ ++ size_t oldsize; /* size of cur before split */ ++ ++ oldsize = cur->size; ++ cur->size = realsize; ++ *(allocated) = cur->size - block_size; ++ nxt = NEXT_SBLOCK(cur); ++ nxt->prev_size = 0; /* block is alloc'd */ ++ nxt->size = oldsize - realsize; /* and fix the size */ ++ NEXT_SBLOCK(nxt)->prev_size = nxt->size; /* adjust size */ ++ SET_CANARY(nxt); ++ ++ /* replace cur with next in free list */ ++ nxt->fnext = cur->fnext; ++ nxt->fprev = cur->fprev; ++ BLOCKAT(nxt->fnext)->fprev = OFFSET(nxt); ++ BLOCKAT(nxt->fprev)->fnext = OFFSET(nxt); ++#ifdef __APC_SMA_DEBUG__ ++ nxt->id = -1; ++#endif ++ } ++ ++ cur->fnext = 0; ++ ++ /* update the block header */ ++ header->avail -= cur->size; ++#if ALLOC_DISTRIBUTION ++ header->adist[(int)(log(size)/log(2))]++; ++#endif ++ ++ SET_CANARY(cur); ++#ifdef __APC_SMA_DEBUG__ ++ cur->id = ++block_id; ++ fprintf(stderr, "allocate(realsize=%d,size=%d,id=%d)\n", (int)(size), (int)(cur->size), cur->id); ++#endif ++ ++ return OFFSET(cur) + block_size; ++} ++/* }}} */ ++ ++/* {{{ sma_deallocate: deallocates the block at the given offset */ ++static APC_HOTSPOT size_t sma_deallocate(void* shmaddr, size_t offset) ++{ ++ sma_header_t* header; /* header of shared memory segment */ ++ block_t* cur; /* the new block to insert */ ++ block_t* prv; /* the block before cur */ ++ block_t* nxt; /* the block after cur */ ++ size_t size; /* size of deallocated block */ ++ ++ offset -= ALIGNWORD(sizeof(struct block_t)); ++ assert(offset >= 0); ++ ++ /* find position of new block in free list */ ++ cur = BLOCKAT(offset); ++ ++ /* update the block header */ ++ header = (sma_header_t*) shmaddr; ++ header->avail += cur->size; ++ size = cur->size; ++ ++ if (cur->prev_size != 0) { ++ /* remove prv from list */ ++ prv = PREV_SBLOCK(cur); ++ BLOCKAT(prv->fnext)->fprev = prv->fprev; ++ BLOCKAT(prv->fprev)->fnext = prv->fnext; ++ /* cur and prv share an edge, combine them */ ++ prv->size +=cur->size; ++ RESET_CANARY(cur); ++ cur = prv; ++ } ++ ++ nxt = NEXT_SBLOCK(cur); ++ if (nxt->fnext != 0) { ++ assert(NEXT_SBLOCK(NEXT_SBLOCK(cur))->prev_size == nxt->size); ++ /* cur and nxt shared an edge, combine them */ ++ BLOCKAT(nxt->fnext)->fprev = nxt->fprev; ++ BLOCKAT(nxt->fprev)->fnext = nxt->fnext; ++ cur->size += nxt->size; ++#ifdef __APC_SMA_DEBUG__ ++ CHECK_CANARY(nxt); ++ nxt->id = -1; /* assert this or set it ? */ ++#endif ++ RESET_CANARY(nxt); ++ } ++ ++ NEXT_SBLOCK(cur)->prev_size = cur->size; ++ ++ /* insert new block after prv */ ++ prv = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); ++ cur->fnext = prv->fnext; ++ prv->fnext = OFFSET(cur); ++ cur->fprev = OFFSET(prv); ++ BLOCKAT(cur->fnext)->fprev = OFFSET(cur); ++ ++ return size; ++} ++/* }}} */ ++ ++/* {{{ apc_sma_init */ ++ ++void apc_sma_init(int numseg, size_t segsize, char *mmap_file_mask TSRMLS_DC) ++{ ++ uint i; ++ ++ if (sma_initialized) { ++ return; ++ } ++ sma_initialized = 1; ++ ++#if APC_MMAP ++ /* ++ * I don't think multiple anonymous mmaps makes any sense ++ * so force sma_numseg to 1 in this case ++ */ ++ if(!mmap_file_mask || ++ (mmap_file_mask && !strlen(mmap_file_mask)) || ++ (mmap_file_mask && !strcmp(mmap_file_mask, "/dev/zero"))) { ++ sma_numseg = 1; ++ } else { ++ sma_numseg = numseg > 0 ? numseg : DEFAULT_NUMSEG; ++ } ++#else ++ sma_numseg = numseg > 0 ? numseg : DEFAULT_NUMSEG; ++#endif ++ ++ sma_segsize = segsize > 0 ? segsize : DEFAULT_SEGSIZE; ++ ++ sma_segments = (apc_segment_t*) apc_emalloc((sma_numseg * sizeof(apc_segment_t)) TSRMLS_CC); ++ ++ for (i = 0; i < sma_numseg; i++) { ++ sma_header_t* header; ++ block_t *first, *empty, *last; ++ void* shmaddr; ++ ++#if APC_MMAP ++ sma_segments[i] = apc_mmap(mmap_file_mask, sma_segsize TSRMLS_CC); ++ if(sma_numseg != 1) memcpy(&mmap_file_mask[strlen(mmap_file_mask)-6], "XXXXXX", 6); ++#else ++ sma_segments[i] = apc_shm_attach(apc_shm_create(i, sma_segsize TSRMLS_CC), sma_segsize TSRMLS_CC); ++#endif ++ ++ sma_segments[i].size = sma_segsize; ++ ++ shmaddr = sma_segments[i].shmaddr; ++ ++ header = (sma_header_t*) shmaddr; ++ apc_lck_create(NULL, 0, 1, header->sma_lock); ++ header->segsize = sma_segsize; ++ header->avail = sma_segsize - ALIGNWORD(sizeof(sma_header_t)) - ALIGNWORD(sizeof(block_t)) - ALIGNWORD(sizeof(block_t)); ++#if ALLOC_DISTRIBUTION ++ { ++ int j; ++ for(j=0; j<30; j++) header->adist[j] = 0; ++ } ++#endif ++ first = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); ++ first->size = 0; ++ first->fnext = ALIGNWORD(sizeof(sma_header_t)) + ALIGNWORD(sizeof(block_t)); ++ first->fprev = 0; ++ first->prev_size = 0; ++ SET_CANARY(first); ++#ifdef __APC_SMA_DEBUG__ ++ block->id = -1; ++#endif ++ empty = BLOCKAT(first->fnext); ++ empty->size = header->avail - ALIGNWORD(sizeof(block_t)); ++ empty->fnext = OFFSET(empty) + empty->size; ++ empty->fprev = ALIGNWORD(sizeof(sma_header_t)); ++ empty->prev_size = 0; ++ SET_CANARY(empty); ++#ifdef __APC_SMA_DEBUG__ ++ empty->id = -1; ++#endif ++ last = BLOCKAT(empty->fnext); ++ last->size = 0; ++ last->fnext = 0; ++ last->fprev = OFFSET(empty); ++ last->prev_size = empty->size; ++ SET_CANARY(last); ++#ifdef __APC_SMA_DEBUG__ ++ last->id = -1; ++#endif ++ } ++} ++/* }}} */ ++ ++/* {{{ apc_sma_cleanup */ ++void apc_sma_cleanup(TSRMLS_D) ++{ ++ uint i; ++ ++ assert(sma_initialized); ++ ++ for (i = 0; i < sma_numseg; i++) { ++ apc_lck_destroy(SMA_LCK(i)); ++#if APC_MMAP ++ apc_unmap(&sma_segments[i] TSRMLS_CC); ++#else ++ apc_shm_detach(&sma_segments[i] TSRMLS_CC); ++#endif ++ } ++ sma_initialized = 0; ++ apc_efree(sma_segments TSRMLS_CC); ++} ++/* }}} */ ++ ++/* {{{ apc_sma_malloc_ex */ ++void* apc_sma_malloc_ex(size_t n, size_t fragment, size_t* allocated TSRMLS_DC) ++{ ++ size_t off; ++ uint i; ++ int nuked = 0; ++ ++restart: ++ assert(sma_initialized); ++ LOCK(SMA_LCK(sma_lastseg)); ++ ++ off = sma_allocate(SMA_HDR(sma_lastseg), n, fragment, allocated); ++ ++ if(off == -1 && APCG(current_cache)) { ++ /* retry failed allocation after we expunge */ ++ UNLOCK(SMA_LCK(sma_lastseg)); ++ APCG(current_cache)->expunge_cb(APCG(current_cache), (n+fragment) TSRMLS_CC); ++ LOCK(SMA_LCK(sma_lastseg)); ++ off = sma_allocate(SMA_HDR(sma_lastseg), n, fragment, allocated); ++ } ++ ++ if (off != -1) { ++ void* p = (void *)(SMA_ADDR(sma_lastseg) + off); ++ UNLOCK(SMA_LCK(sma_lastseg)); ++#ifdef VALGRIND_MALLOCLIKE_BLOCK ++ VALGRIND_MALLOCLIKE_BLOCK(p, n, 0, 0); ++#endif ++ return p; ++ } ++ ++ UNLOCK(SMA_LCK(sma_lastseg)); ++ ++ for (i = 0; i < sma_numseg; i++) { ++ if (i == sma_lastseg) { ++ continue; ++ } ++ LOCK(SMA_LCK(i)); ++ off = sma_allocate(SMA_HDR(i), n, fragment, allocated); ++ if(off == -1 && APCG(current_cache)) { ++ /* retry failed allocation after we expunge */ ++ UNLOCK(SMA_LCK(i)); ++ APCG(current_cache)->expunge_cb(APCG(current_cache), (n+fragment) TSRMLS_CC); ++ LOCK(SMA_LCK(i)); ++ off = sma_allocate(SMA_HDR(i), n, fragment, allocated); ++ } ++ if (off != -1) { ++ void* p = (void *)(SMA_ADDR(i) + off); ++ UNLOCK(SMA_LCK(i)); ++ sma_lastseg = i; ++#ifdef VALGRIND_MALLOCLIKE_BLOCK ++ VALGRIND_MALLOCLIKE_BLOCK(p, n, 0, 0); ++#endif ++ return p; ++ } ++ UNLOCK(SMA_LCK(i)); ++ } ++ ++ /* I've tried being nice, but now you're just asking for it */ ++ if(!nuked) { ++ apc_cache->expunge_cb(apc_cache, (n+fragment) TSRMLS_CC); ++ apc_user_cache->expunge_cb(apc_user_cache, (n+fragment) TSRMLS_CC); ++ nuked = 1; ++ goto restart; ++ } ++ ++ /* now, I've truly and well given up */ ++ ++ return NULL; ++} ++/* }}} */ ++ ++/* {{{ apc_sma_malloc */ ++void* apc_sma_malloc(size_t n TSRMLS_DC) ++{ ++ size_t allocated; ++ void *p = apc_sma_malloc_ex(n, MINBLOCKSIZE, &allocated TSRMLS_CC); ++ ++ return p; ++} ++/* }}} */ ++ ++/* {{{ apc_sma_realloc */ ++void* apc_sma_realloc(void *p, size_t n TSRMLS_DC) ++{ ++ apc_sma_free(p TSRMLS_CC); ++ return apc_sma_malloc(n TSRMLS_CC); ++} ++/* }}} */ ++ ++/* {{{ apc_sma_strdup */ ++char* apc_sma_strdup(const char* s TSRMLS_DC) ++{ ++ void* q; ++ int len; ++ ++ if(!s) return NULL; ++ ++ len = strlen(s)+1; ++ q = apc_sma_malloc(len TSRMLS_CC); ++ if(!q) return NULL; ++ memcpy(q, s, len); ++ return q; ++} ++/* }}} */ ++ ++/* {{{ apc_sma_free */ ++void apc_sma_free(void* p TSRMLS_DC) ++{ ++ uint i; ++ size_t offset; ++ size_t d_size; + -+ if (graphics_avail()) { -+ $size='width='.(2*GRAPH_SIZE+150).' height='.(GRAPH_SIZE+10); -+ echo << -+EOB; -+ } -+ echo <<Fragmentation: $frag -+
    $range$v
    -+
    -+EOB; -+ -+ break; ++ } + ++ apc_error("apc_sma_free: could not locate address %p" TSRMLS_CC, p); ++} ++/* }}} */ + -+// ----------------------------------------------- -+// User Cache Entries -+// ----------------------------------------------- -+case OB_USER_CACHE: -+ if (!$AUTHENTICATED) { -+ echo '
    You need to login to see the user values here!
     
    '; -+ put_login_link("Login now!"); -+ echo '
    '; -+ break; -+ } -+ $fieldname='info'; -+ $fieldheading='User Entry Label'; -+ $fieldkey='info'; ++#ifdef APC_MEMPROTECT ++/* {{{ */ ++void* apc_sma_protect(void *p) ++{ ++ unsigned int i = 0; ++ size_t offset; + ++ if (p == NULL) { ++ return NULL; ++ } + -+// ----------------------------------------------- -+// System Cache Entries -+// ----------------------------------------------- -+case OB_SYS_CACHE: -+ if (!isset($fieldname)) -+ { -+ $fieldname='filename'; -+ $fieldheading='Script Filename'; -+ if(ini_get("apc.stat")) $fieldkey='inode'; -+ else $fieldkey='filename'; -+ } -+ if (!empty($MYREQUEST['SH'])) -+ { -+ echo <<< EOB -+
    -+ -+EOB; ++ if(SMA_RO(sma_lastseg) == NULL) return p; + -+ $m=0; -+ foreach($scope_list as $j => $list) { -+ foreach($cache[$list] as $i => $entry) { -+ if (md5($entry[$fieldkey])!=$MYREQUEST['SH']) continue; -+ foreach($entry as $k => $value) { -+ if (!$AUTHENTICATED) { -+ // hide all path entries if not logged in -+ $value=preg_replace('/^.*(\\/|\\\\)/','<hidden>/',$value); -+ } ++ offset = (size_t)((char *)p - SMA_ADDR(sma_lastseg)); + -+ if ($k == "num_hits") { -+ $value=sprintf("%s (%.2f%%)",$value,$value*100/$cache['num_hits']); -+ } -+ if ($k == 'deletion_time') { -+ if(!$entry['deletion_time']) $value = "None"; -+ } -+ echo -+ "", -+ "", -+ "", -+ ""; -+ $m=1-$m; -+ } -+ if($fieldkey=='info') { -+ echo "\n"; -+ } -+ break; -+ } -+ } ++ if(p >= (void*)SMA_ADDR(sma_lastseg) && offset < sma_segsize) { ++ return SMA_RO(sma_lastseg) + offset; ++ } + -+ echo <<
    AttributeValue
    ",ucwords(preg_replace("/_/"," ",$k)),"",(preg_match("/time/",$k) && $value!='None') ? date(DATE_FORMAT,$value) : $value,"
    Stored Value
    ";
    -+					$output = var_export(apc_fetch($entry[$fieldkey]),true);
    -+					echo htmlspecialchars($output);
    -+					echo "
    -+
    -+EOB; -+ break; -+ } ++ for (i = 0; i < sma_numseg; i++) { ++ offset = (size_t)((char *)p - SMA_ADDR(i)); ++ if (p >= (void*)SMA_ADDR(i) && offset < sma_segsize) { ++ return SMA_RO(i) + offset; ++ } ++ } + -+ $cols=6; -+ echo <<
    Scope: -+ -+ ", -+ ", Sorting:', -+ '', -+ '', -+ '  Search: ', -+ ' ', -+ '
    ', ++ return NULL; ++} ++/* }}} */ + -+ '
    ', -+ '', -+ '', -+ '', -+ '', -+ '', -+ '', -+ ''; ++/* {{{ */ ++void* apc_sma_unprotect(void *p) ++{ ++ unsigned int i = 0; ++ size_t offset; + -+ if($fieldname=='info') { -+ $cols+=2; -+ echo ''; -+ } -+ echo ''; ++ if (p == NULL) { ++ return NULL; ++ } + -+ // builds list with alpha numeric sortable keys -+ // -+ $list = array(); -+ foreach($cache[$scope_list[$MYREQUEST['SCOPE']]] as $i => $entry) { -+ switch($MYREQUEST['SORT1']) { -+ case 'A': $k=sprintf('%015d-',$entry['access_time']); break; -+ case 'H': $k=sprintf('%015d-',$entry['num_hits']); break; -+ case 'Z': $k=sprintf('%015d-',$entry['mem_size']); break; -+ case 'M': $k=sprintf('%015d-',$entry['mtime']); break; -+ case 'C': $k=sprintf('%015d-',$entry['creation_time']); break; -+ case 'T': $k=sprintf('%015d-',$entry['ttl']); break; -+ case 'D': $k=sprintf('%015d-',$entry['deletion_time']); break; -+ case 'S': $k=''; break; -+ } -+ if (!$AUTHENTICATED) { -+ // hide all path entries if not logged in -+ $list[$k.$entry[$fieldname]]=preg_replace('/^.*(\\/|\\\\)/','<hidden>/',$entry); -+ } else { -+ $list[$k.$entry[$fieldname]]=$entry; -+ } -+ } ++ if(SMA_RO(sma_lastseg) == NULL) return p; + -+ if ($list) { -+ -+ // sort list -+ // -+ switch ($MYREQUEST['SORT2']) { -+ case "A": krsort($list); break; -+ case "D": ksort($list); break; -+ } -+ -+ // output list -+ $i=0; -+ foreach($list as $k => $entry) { -+ if(!$MYREQUEST['SEARCH'] || preg_match('/'.$MYREQUEST['SEARCH'].'/i', $entry[$fieldname]) != 0) { -+ echo -+ '', -+ "', -+ '', -+ '', -+ '', -+ '', -+ ''; ++ offset = (size_t)((char *)p - SMA_RO(sma_lastseg)); + -+ if($fieldname=='info') { -+ if($entry['ttl']) -+ echo ''; -+ else -+ echo ''; ++ if(p >= (void*)SMA_RO(sma_lastseg) && offset < sma_segsize) { ++ return SMA_ADDR(sma_lastseg) + offset; ++ } ++ ++ for (i = 0; i < sma_numseg; i++) { ++ offset = (size_t)((char *)p - SMA_RO(i)); ++ if (p >= (void*)SMA_RO(i) && offset < sma_segsize) { ++ return SMA_ADDR(i) + offset; + } -+ echo -+ '', -+ ''; -+ $i++; -+ if ($i == $MYREQUEST['COUNT']) -+ break; -+ } -+ } -+ -+ } else { -+ echo ''; -+ } -+ echo <<< EOB -+
    ',sortheader('S',$fieldheading, "&OB=".$MYREQUEST['OB']),'',sortheader('H','Hits', "&OB=".$MYREQUEST['OB']),'',sortheader('Z','Size', "&OB=".$MYREQUEST['OB']),'',sortheader('A','Last accessed',"&OB=".$MYREQUEST['OB']),'',sortheader('M','Last modified',"&OB=".$MYREQUEST['OB']),'',sortheader('C','Created at', "&OB=".$MYREQUEST['OB']),'',sortheader('T','Timeout',"&OB=".$MYREQUEST['OB']),'',sortheader('D','Deleted at',"&OB=".$MYREQUEST['OB']),'
    ",$entry[$fieldname],'',$entry['num_hits'],'',$entry['mem_size'],'',date(DATE_FORMAT,$entry['access_time']),'',date(DATE_FORMAT,$entry['mtime']),'',date(DATE_FORMAT,$entry['creation_time']),''.$entry['ttl'].' secondsNone',$entry['deletion_time'] ? date(DATE_FORMAT,$entry['deletion_time']) : '-','
    No data
    -+EOB; ++ } + -+ if ($list && $i < count($list)) { -+ echo "",count($list)-$i,' more available...'; -+ } ++ return NULL; ++} ++/* }}} */ ++#else ++/* {{{ */ ++void* apc_sma_protect(void *p) { return p; } ++void* apc_sma_unprotect(void *p) { return p; } ++/* }}} */ ++#endif ++ ++/* {{{ apc_sma_info */ ++apc_sma_info_t* apc_sma_info(zend_bool limited TSRMLS_DC) ++{ ++ apc_sma_info_t* info; ++ apc_sma_link_t** link; ++ uint i; ++ char* shmaddr; ++ block_t* prv; ++ ++ if (!sma_initialized) { ++ return NULL; ++ } ++ ++ info = (apc_sma_info_t*) apc_emalloc(sizeof(apc_sma_info_t) TSRMLS_CC); ++ info->num_seg = sma_numseg; ++ info->seg_size = sma_segsize - (ALIGNWORD(sizeof(sma_header_t)) + ALIGNWORD(sizeof(block_t)) + ALIGNWORD(sizeof(block_t))); + -+ echo <<< EOB -+
    -+EOB; -+ break; ++ info->list = apc_emalloc(info->num_seg * sizeof(apc_sma_link_t*) TSRMLS_CC); ++ for (i = 0; i < sma_numseg; i++) { ++ info->list[i] = NULL; ++ } + ++ if(limited) return info; + -+// ----------------------------------------------- -+// Per-Directory System Cache Entries -+// ----------------------------------------------- -+case OB_SYS_CACHE_DIR: -+ if (!$AUTHENTICATED) { -+ break; -+ } ++ /* For each segment */ ++ for (i = 0; i < sma_numseg; i++) { ++ RDLOCK(SMA_LCK(i)); ++ shmaddr = SMA_ADDR(i); ++ prv = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); + -+ echo <<
    Scope: -+ -+ ", -+ ", Sorting:', -+ '', -+ '', -+ ", Group By Dir Level:', -+ ' ', -+ '
    ', ++ link = &info->list[i]; + -+ '
    ', -+ '', -+ '', -+ '', -+ '', -+ '', -+ '', -+ '', -+ ''; ++ /* For each block in this segment */ ++ while (BLOCKAT(prv->fnext)->fnext != 0) { ++ block_t* cur = BLOCKAT(prv->fnext); ++#ifdef __APC_SMA_DEBUG__ ++ CHECK_CANARY(cur); ++#endif + -+ // builds list with alpha numeric sortable keys -+ // -+ $tmp = $list = array(); -+ foreach($cache[$scope_list[$MYREQUEST['SCOPE']]] as $entry) { -+ $n = dirname($entry['filename']); -+ if ($MYREQUEST['AGGR'] > 0) { -+ $n = preg_replace("!^(/?(?:[^/\\\\]+[/\\\\]){".($MYREQUEST['AGGR']-1)."}[^/\\\\]*).*!", "$1", $n); -+ } -+ if (!isset($tmp[$n])) { -+ $tmp[$n] = array('hits'=>0,'size'=>0,'ents'=>0); -+ } -+ $tmp[$n]['hits'] += $entry['num_hits']; -+ $tmp[$n]['size'] += $entry['mem_size']; -+ ++$tmp[$n]['ents']; -+ } ++ *link = apc_emalloc(sizeof(apc_sma_link_t) TSRMLS_CC); ++ (*link)->size = cur->size; ++ (*link)->offset = prv->fnext; ++ (*link)->next = NULL; ++ link = &(*link)->next; + -+ foreach ($tmp as $k => $v) { -+ switch($MYREQUEST['SORT1']) { -+ case 'A': $kn=sprintf('%015d-',$v['size'] / $v['ents']);break; -+ case 'T': $kn=sprintf('%015d-',$v['ents']); break; -+ case 'H': $kn=sprintf('%015d-',$v['hits']); break; -+ case 'Z': $kn=sprintf('%015d-',$v['size']); break; -+ case 'C': $kn=sprintf('%015d-',$v['hits'] / $v['ents']);break; -+ case 'S': $kn = $k; break; -+ } -+ $list[$kn.$k] = array($k, $v['ents'], $v['hits'], $v['size']); -+ } ++ prv = cur; + -+ if ($list) { -+ -+ // sort list -+ // -+ switch ($MYREQUEST['SORT2']) { -+ case "A": krsort($list); break; -+ case "D": ksort($list); break; -+ } -+ -+ // output list -+ $i = 0; -+ foreach($list as $entry) { -+ echo -+ '', -+ "', -+ '', -+ '', -+ '', -+ '', -+ '', -+ ''; ++#if ALLOC_DISTRIBUTION ++ sma_header_t* header = (sma_header_t*) segment->shmaddr; ++ memcpy(info->seginfo[i].adist, header->adist, sizeof(size_t) * 30); ++#endif + -+ if (++$i == $MYREQUEST['COUNT']) break; -+ } -+ -+ } else { -+ echo ''; -+ } -+ echo <<< EOB -+
    ',sortheader('S','Directory Name', "&OB=".$MYREQUEST['OB']),'',sortheader('T','Number of Files',"&OB=".$MYREQUEST['OB']),'',sortheader('H','Total Hits', "&OB=".$MYREQUEST['OB']),'',sortheader('Z','Total Size', "&OB=".$MYREQUEST['OB']),'',sortheader('C','Avg. Hits', "&OB=".$MYREQUEST['OB']),'',sortheader('A','Avg. Size', "&OB=".$MYREQUEST['OB']),'
    ",$entry[0],'',$entry[1],'',$entry[2],'',$entry[3],'',round($entry[2] / $entry[1]),'',round($entry[3] / $entry[1]),'
    No data
    -+EOB; ++ } ++ RDUNLOCK(SMA_LCK(i)); ++ } + -+ if ($list && $i < count($list)) { -+ echo "",count($list)-$i,' more available...'; -+ } ++ return info; ++} ++/* }}} */ + -+ echo <<< EOB -+
    -+EOB; -+ break; ++/* {{{ apc_sma_free_info */ ++void apc_sma_free_info(apc_sma_info_t* info TSRMLS_DC) ++{ ++ int i; + -+// ----------------------------------------------- -+// Version check -+// ----------------------------------------------- -+case OB_VERSION_CHECK: -+ echo <<

    APC Version Information

    -+ -+ -+ -+ -+EOB; ++ for (i = 0; i < info->num_seg; i++) { ++ apc_sma_link_t* p = info->list[i]; ++ while (p) { ++ apc_sma_link_t* q = p; ++ p = p->next; ++ apc_efree(q TSRMLS_CC); ++ } ++ } ++ apc_efree(info->list TSRMLS_CC); ++ apc_efree(info TSRMLS_CC); ++} ++/* }}} */ + -+ $rss = @file_get_contents("http://pecl.php.net/feeds/pkg_apc.rss"); -+ if (!$rss) { -+ echo ''; -+ } else { -+ $apcversion = phpversion('apc'); ++/* {{{ apc_sma_get_avail_mem */ ++size_t apc_sma_get_avail_mem() ++{ ++ size_t avail_mem = 0; ++ uint i; + -+ preg_match('!APC ([0-9.]+)!', $rss, $match); -+ echo ''; -+ echo ''; -+ } -+ echo <<< EOB -+
    Unable to fetch version information.
    '; -+ if (version_compare($apcversion, $match[1], '>=')) { -+ echo '
    You are running the latest version of APC ('.$apcversion.')
    '; -+ $i = 3; -+ } else { -+ echo '
    You are running an older version of APC ('.$apcversion.'), -+ newer version '.$match[1].' is available at -+ http://pecl.php.net/package/APC/'.$match[1].' -+
    '; -+ $i = -1; -+ } -+ echo '

    Change Log:


    '; ++ for (i = 0; i < sma_numseg; i++) { ++ sma_header_t* header = SMA_HDR(i); ++ avail_mem += header->avail; ++ } ++ return avail_mem; ++} ++/* }}} */ + -+ preg_match_all('!<(title|description)>([^<]+)!', $rss, $match); -+ next($match[2]); next($match[2]); ++/* {{{ apc_sma_get_avail_size */ ++zend_bool apc_sma_get_avail_size(size_t size) ++{ ++ uint i; + -+ while (list(,$v) = each($match[2])) { -+ list(,$ver) = explode(' ', $v, 2); -+ if ($i < 0 && version_compare($apcversion, $ver, '>=')) { -+ break; -+ } else if (!$i--) { -+ break; -+ } -+ echo "".htmlspecialchars($v)."
    "; -+ echo nl2br(htmlspecialchars(current($match[2])))."
    "; -+ next($match[2]); ++ for (i = 0; i < sma_numseg; i++) { ++ sma_header_t* header = SMA_HDR(i); ++ if (header->avail > size) { ++ return 1; + } -+ echo '
    -+ -+EOB; -+ break; -+ ++ } ++ return 0; +} ++/* }}} */ + -+echo <<< EOB -+ -+EOB; + -+?> ++#if ALLOC_DISTRIBUTION ++size_t *apc_sma_get_alloc_distribution(void) { ++ sma_header_t* header = (sma_header_t*) segment->sma_shmaddr; ++ return header->adist; ++} ++#endif + -+ -+ -+ -Index: php-5.2.3/ext/apc/apc_php.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_php.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,71 @@ ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_sma.h b/ext/apc/apc_sma.h +--- a/ext/apc/apc_sma.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_sma.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,103 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -8237,10 +13249,6 @@ Index: php-5.2.3/ext/apc/apc_php.h + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | -+ | George Schlossnagle | -+ | Rasmus Lerdorf | -+ | Arun C. Murthy | -+ | Gopal Vijayaraghavan | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 @@ -8253,35 +13261,71 @@ Index: php-5.2.3/ext/apc/apc_php.h + + */ + -+/* $Id: apc_php.h,v 3.10 2006/11/16 20:24:48 gopalv Exp $ */ ++/* $Id: apc_sma.h 307048 2011-01-03 23:53:17Z kalle $ */ + -+#ifndef APC_PHP_H -+#define APC_PHP_H ++#ifndef APC_SMA_H ++#define APC_SMA_H + -+/* -+ * The purpose of this header file is to include all PHP and Zend headers that -+ * are typically needed elsewhere in APC. This makes it easy to insure that -+ * all required headers are available. -+ */ ++#define ALLOC_DISTRIBUTION 0 + -+#include "php.h" -+#include "zend.h" -+#include "zend_API.h" -+#include "zend_compile.h" -+#include "zend_hash.h" -+#include "zend_extensions.h" ++#include "apc.h" + -+#if ZEND_MODULE_API_NO > 20050922 -+#define ZEND_ENGINE_2_2 -+#endif -+#if ZEND_MODULE_API_NO > 20050921 -+#define ZEND_ENGINE_2_1 ++/* Simple shared memory allocator */ ++ ++typedef struct _apc_segment_t apc_segment_t; ++ ++struct _apc_segment_t { ++ size_t size; ++ void* shmaddr; ++#ifdef APC_MEMPROTECT ++ void* roaddr; +#endif -+#ifdef ZEND_ENGINE_2_1 -+#include "zend_vm.h" ++}; ++ ++extern void apc_sma_init(int numseg, size_t segsize, char *mmap_file_mask TSRMLS_DC); ++extern void apc_sma_cleanup(TSRMLS_D); ++extern void* apc_sma_malloc(size_t size TSRMLS_DC); ++extern void* apc_sma_malloc_ex(size_t size, size_t fragment, size_t* allocated TSRMLS_DC); ++extern void* apc_sma_realloc(void* p, size_t size TSRMLS_DC); ++extern char* apc_sma_strdup(const char *s TSRMLS_DC); ++extern void apc_sma_free(void* p TSRMLS_DC); ++#if ALLOC_DISTRIBUTION ++extern size_t *apc_sma_get_alloc_distribution(); +#endif + -+#include "rfc1867.h" ++extern void* apc_sma_protect(void *p); ++extern void* apc_sma_unprotect(void *p); ++ ++/* {{{ struct definition: apc_sma_link_t */ ++typedef struct apc_sma_link_t apc_sma_link_t; ++struct apc_sma_link_t { ++ long size; /* size of this free block */ ++ long offset; /* offset in segment of this block */ ++ apc_sma_link_t* next; /* link to next free block */ ++}; ++/* }}} */ ++ ++/* {{{ struct definition: apc_sma_info_t */ ++typedef struct apc_sma_info_t apc_sma_info_t; ++struct apc_sma_info_t { ++ int num_seg; /* number of shared memory segments */ ++ size_t seg_size; /* size of each shared memory segment */ ++ apc_sma_link_t** list; /* there is one list per segment */ ++}; ++/* }}} */ ++ ++extern apc_sma_info_t* apc_sma_info(zend_bool limited TSRMLS_DC); ++extern void apc_sma_free_info(apc_sma_info_t* info TSRMLS_DC); ++ ++extern size_t apc_sma_get_avail_mem(); ++extern zend_bool apc_sma_get_avail_size(size_t size); ++extern void apc_sma_check_integrity(); ++ ++/* {{{ ALIGNWORD: pad up x, aligned to the system's word boundary */ ++typedef union { void* p; int i; long l; double d; void (*f)(); } apc_word_t; ++#define ALIGNSIZE(x, size) ((size) * (1 + (((x)-1)/(size)))) ++#define ALIGNWORD(x) ALIGNSIZE(x, sizeof(apc_word_t)) ++/* }}} */ + +#endif + @@ -8290,19 +13334,18 @@ Index: php-5.2.3/ext/apc/apc_php.h + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_pthreadmutex.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_pthreadmutex.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,104 @@ +diff -Naur a/ext/apc/apc_spin.c b/ext/apc/apc_spin.c +--- a/ext/apc/apc_spin.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_spin.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,66 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -8317,78 +13360,40 @@ Index: php-5.2.3/ext/apc/apc_pthreadmutex.c + + */ + -+/* $Id: apc_pthreadmutex.c,v 3.2 2007/02/15 21:40:45 shire Exp $ */ -+ -+#include "apc_pthreadmutex.h" -+ -+#ifdef APC_PTHREADMUTEX_LOCKS -+ -+pthread_mutex_t *apc_pthreadmutex_create(pthread_mutex_t *lock) -+{ -+ int result; -+ pthread_mutexattr_t* attr; -+ attr = malloc(sizeof(pthread_mutexattr_t)); ++/* $Id: apc_spin.c 307048 2011-01-03 23:53:17Z kalle $ */ + -+ result = pthread_mutexattr_init(attr); -+ if(result == ENOMEM) { -+ apc_eprint("pthread mutex error: Insufficient memory exists to create the mutex attribute object."); -+ } else if(result == EINVAL) { -+ apc_eprint("pthread mutex error: attr does not point to writeable memory."); -+ } else if(result == EFAULT) { -+ apc_eprint("pthread mutex error: attr is an invalid pointer."); -+ } ++#include "apc_spin.h" + -+ /* pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ERRORCHECK); */ -+ result = pthread_mutexattr_setpshared(attr, PTHREAD_PROCESS_SHARED); -+ if(result == EINVAL) { -+ apc_eprint("pthread mutex error: attr is not an initialized mutex attribute object, or pshared is not a valid process-shared state setting."); -+ } else if(result == EFAULT) { -+ apc_eprint("pthread mutex error: attr is an invalid pointer."); -+ } else if(result == ENOTSUP) { -+ apc_eprint("pthread mutex error: pshared was set to PTHREAD_PROCESS_SHARED."); -+ } ++#ifdef APC_SPIN_LOCKS + -+ if(pthread_mutex_init(lock, attr)) { -+ apc_eprint("unable to initialize pthread lock"); -+ } -+ return lock; ++slock_t *apc_slock_create(slock_t *lock) ++{ ++ S_INIT_LOCK(lock); ++ return lock; +} + -+void apc_pthreadmutex_destroy(pthread_mutex_t *lock) ++void apc_slock_destroy(slock_t *lock) +{ -+ return; /* we don't actually destroy the mutex, as it would destroy it for all processes */ ++ return; +} + -+void apc_pthreadmutex_lock(pthread_mutex_t *lock) ++void apc_slock_lock(slock_t *lock TSRMLS_DC) +{ -+ int result; -+ result = pthread_mutex_lock(lock); -+ if(result == EINVAL) { -+ apc_eprint("unable to obtain pthread lock (EINVAL)"); -+ } else if(result == EDEADLK) { -+ apc_eprint("unable to obtain pthread lock (EDEADLK)"); -+ } ++ S_LOCK(lock); +} + -+void apc_pthreadmutex_unlock(pthread_mutex_t *lock) ++void apc_slock_unlock(slock_t *lock) +{ -+ if(pthread_mutex_unlock(lock)) { -+ apc_eprint("unable to unlock pthread lock"); -+ } ++ S_UNLOCK(lock); +} + -+zend_bool apc_pthreadmutex_nonblocking_lock(pthread_mutex_t *lock) ++zend_bool apc_slock_nonblocking_lock(slock_t *lock) +{ -+ int rval; -+ rval = pthread_mutex_trylock(lock); -+ if(rval == EBUSY) { /* Lock is already held */ -+ return 0; -+ } else if(rval == 0) { /* Obtained lock */ -+ return 1; -+ } else { /* Other error */ -+ apc_eprint("unable to obtain pthread trylock"); -+ return 0; -+ } ++ /* Technically we aren't supposed to call this directly, but the original ++ * code provides no method for absolute non-blocking locks, so we'll call into ++ * the TAS (test and set) functionality directly ++ */ ++ return !(TAS(lock)); /* if TAS returns 0 we obtained the lock, otherwise we failed */ +} + + @@ -8399,19 +13404,18 @@ Index: php-5.2.3/ext/apc/apc_pthreadmutex.c + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_pthreadmutex.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_pthreadmutex.h 2007-07-30 10:52:17.000000000 -0500 +diff -Naur a/ext/apc/apc_spin.h b/ext/apc/apc_spin.h +--- a/ext/apc/apc_spin.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_spin.h 2012-07-20 00:10:35.000000000 +0200 @@ -0,0 +1,48 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -8426,22 +13430,22 @@ Index: php-5.2.3/ext/apc/apc_pthreadmutex.h + + */ + -+/* $Id: apc_pthreadmutex.h,v 3.3 2007/01/28 07:53:57 shire Exp $ */ ++/* $Id: apc_spin.h 307048 2011-01-03 23:53:17Z kalle $ */ + -+#ifndef APC_PTHREADMUTEX_H -+#define APC_PTHREADMUTEX_H ++#ifndef APC_SPIN_H ++#define APC_SPIN_H + +#include "apc.h" + -+#ifdef APC_PTHREADMUTEX_LOCKS ++#ifdef APC_SPIN_LOCKS + -+#include ++#include "pgsql_s_lock.h" + -+pthread_mutex_t *apc_pthreadmutex_create(); -+void apc_pthreadmutex_destroy(pthread_mutex_t *lock); -+void apc_pthreadmutex_lock(pthread_mutex_t *lock); -+void apc_pthreadmutex_unlock(pthread_mutex_t *lock); -+zend_bool apc_pthreadmutex_nonblocking_lock(pthread_mutex_t *lock); ++slock_t *apc_slock_create(slock_t *lock); ++void apc_slock_destroy(slock_t *lock); ++void apc_slock_lock(slock_t *lock TSRMLS_DC); ++zend_bool apc_slock_nonblocking_lock(slock_t *lock); ++void apc_slock_unlock(slock_t *lock); + +#endif + @@ -8452,19 +13456,18 @@ Index: php-5.2.3/ext/apc/apc_pthreadmutex.h + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_rfc1867.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_rfc1867.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,175 @@ +diff -Naur a/ext/apc/apc_stack.c b/ext/apc/apc_stack.c +--- a/ext/apc/apc_stack.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_stack.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,106 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -8474,7 +13477,7 @@ Index: php-5.2.3/ext/apc/apc_rfc1867.c + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ -+ | Authors: Rasmus Lerdorf | ++ | Authors: Daniel Cowgill | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 @@ -8487,164 +13490,94 @@ Index: php-5.2.3/ext/apc/apc_rfc1867.c + + */ + -+/* $Id: apc_rfc1867.c,v 3.4 2007/02/24 11:45:29 rasmus Exp $*/ ++/* $Id: apc_stack.c 307048 2011-01-03 23:53:17Z kalle $ */ + +#include "apc.h" -+#include "rfc1867.h" ++#include "apc_stack.h" + -+#ifdef MULTIPART_EVENT_FORMDATA -+extern int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC); ++struct apc_stack_t { ++ void** data; ++ int capacity; ++ int size; ++}; + -+static double my_time() { -+ struct timeval a; -+ double t; -+ gettimeofday(&a, NULL); -+ t = a.tv_sec + (a.tv_usec/1000000); -+ return t; -+} ++apc_stack_t* apc_stack_create(int size_hint TSRMLS_DC) ++{ ++ apc_stack_t* stack = (apc_stack_t*) apc_emalloc(sizeof(apc_stack_t) TSRMLS_CC); + -+void apc_rfc1867_progress(unsigned int event, void *event_data, void **extra TSRMLS_DC) { -+ static char tracking_key[64]; -+ static int key_length = 0; -+ static size_t content_length = 0; -+ static char filename[128]; -+ static char name[64]; -+ static char *temp_filename=NULL; -+ static int cancel_upload = 0; -+ static double start_time; -+ static size_t bytes_processed = 0; -+ static double rate; -+ zval *track = NULL; ++ stack->capacity = (size_hint > 0) ? size_hint : 10; ++ stack->size = 0; ++ stack->data = (void**) apc_emalloc(sizeof(void*) * stack->capacity TSRMLS_CC); + -+ switch (event) { -+ case MULTIPART_EVENT_START: -+ { -+ multipart_event_start *data = (multipart_event_start *) event_data; -+ content_length = data->content_length; -+ *tracking_key = '\0'; -+ *name = '\0'; -+ cancel_upload = 0; -+ temp_filename = NULL; -+ *filename= '\0'; -+ key_length = 0; -+ start_time = my_time(); -+ bytes_processed = 0; -+ rate = 0; -+ } -+ break; ++ return stack; ++} + -+ case MULTIPART_EVENT_FORMDATA: -+ { -+ multipart_event_formdata *data = (multipart_event_formdata *) event_data; ++void apc_stack_destroy(apc_stack_t* stack TSRMLS_DC) ++{ ++ if (stack != NULL) { ++ apc_efree(stack->data TSRMLS_CC); ++ apc_efree(stack TSRMLS_CC); ++ } ++} + -+ if(data->name && !strncasecmp(data->name,"apc_upload_progress",19) && data->value && data->length && data->length < 58) { -+ strlcat(tracking_key, "upload_", 63); -+ strlcat(tracking_key, *data->value, 63); -+ key_length = data->length+7; -+ bytes_processed = data->post_bytes_processed; -+ } -+ } -+ break; ++void apc_stack_clear(apc_stack_t* stack) ++{ ++ assert(stack != NULL); ++ stack->size = 0; ++} + -+ case MULTIPART_EVENT_FILE_START: -+ if(*tracking_key) { -+ multipart_event_file_start *data = (multipart_event_file_start *) event_data; ++void apc_stack_push(apc_stack_t* stack, void* item TSRMLS_DC) ++{ ++ assert(stack != NULL); ++ if (stack->size == stack->capacity) { ++ stack->capacity *= 2; ++ stack->data = apc_erealloc(stack->data, sizeof(void*)*stack->capacity TSRMLS_CC); ++ } ++ stack->data[stack->size++] = item; ++} + -+ bytes_processed = data->post_bytes_processed; -+ strncpy(filename,*data->filename,127); -+ temp_filename = NULL; -+ strncpy(name,data->name,63); -+ ALLOC_INIT_ZVAL(track); -+ array_init(track); -+ add_assoc_long(track, "total", content_length); -+ add_assoc_long(track, "current", bytes_processed); -+ add_assoc_string(track, "filename", filename, 1); -+ add_assoc_string(track, "name", name, 1); -+ add_assoc_long(track, "done", 0); -+ _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC); -+ zval_ptr_dtor(&track); -+ } -+ break; ++void* apc_stack_pop(apc_stack_t* stack) ++{ ++ assert(stack != NULL && stack->size > 0); ++ return stack->data[--stack->size]; ++} + -+ case MULTIPART_EVENT_FILE_DATA: -+ if(*tracking_key) { -+ multipart_event_file_data *data = (multipart_event_file_data *) event_data; -+ bytes_processed = data->post_bytes_processed; -+ ALLOC_INIT_ZVAL(track); -+ array_init(track); -+ add_assoc_long(track, "total", content_length); -+ add_assoc_long(track, "current", bytes_processed); -+ add_assoc_string(track, "filename", filename, 1); -+ add_assoc_string(track, "name", name, 1); -+ add_assoc_long(track, "done", 0); -+ _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC); -+ zval_ptr_dtor(&track); -+ } -+ break; ++void* apc_stack_top(apc_stack_t* stack) ++{ ++ assert(stack != NULL && stack->size > 0); ++ return stack->data[stack->size-1]; ++} + -+ case MULTIPART_EVENT_FILE_END: -+ if(*tracking_key) { -+ multipart_event_file_end *data = (multipart_event_file_end *) event_data; -+ bytes_processed = data->post_bytes_processed; -+ cancel_upload = data->cancel_upload; -+ temp_filename = data->temp_filename; -+ ALLOC_INIT_ZVAL(track); -+ array_init(track); -+ add_assoc_long(track, "total", content_length); -+ add_assoc_long(track, "current", bytes_processed); -+ add_assoc_string(track, "filename", filename, 1); -+ add_assoc_string(track, "name", name, 1); -+ add_assoc_string(track, "temp_filename", temp_filename, 1); -+ add_assoc_long(track, "cancel_upload", cancel_upload); -+ add_assoc_long(track, "done", 0); -+ _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC); -+ zval_ptr_dtor(&track); -+ } -+ break; ++void* apc_stack_get(apc_stack_t* stack, int n) ++{ ++ assert(stack != NULL && stack->size > n); ++ return stack->data[n]; ++} + -+ case MULTIPART_EVENT_END: -+ if(*tracking_key) { -+ double now = my_time(); -+ multipart_event_end *data = (multipart_event_end *) event_data; -+ bytes_processed = data->post_bytes_processed; -+ if(now>start_time) rate = 8.0*bytes_processed/(now-start_time); -+ else rate = 8.0*bytes_processed; /* Too quick */ -+ ALLOC_INIT_ZVAL(track); -+ array_init(track); -+ add_assoc_long(track, "total", content_length); -+ add_assoc_long(track, "current", bytes_processed); -+ add_assoc_double(track, "rate", rate); -+ add_assoc_string(track, "filename", filename, 1); -+ add_assoc_string(track, "name", name, 1); -+ add_assoc_string(track, "temp_filename", temp_filename, 1); -+ add_assoc_long(track, "cancel_upload", cancel_upload); -+ add_assoc_long(track, "done", 1); -+ _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC); -+ zval_ptr_dtor(&track); -+ } -+ break; -+ } ++int apc_stack_size(apc_stack_t* stack) ++{ ++ assert(stack != NULL); ++ return stack->size; +} + -+#endif ++ +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_sem.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_sem.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,177 @@ +diff -Naur a/ext/apc/apc_stack.h b/ext/apc/apc_stack.h +--- a/ext/apc/apc_stack.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_stack.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,58 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -8655,6 +13588,68 @@ Index: php-5.2.3/ext/apc/apc_sem.c + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | ++ | George Schlossnagle | ++ +----------------------------------------------------------------------+ ++ ++ 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_stack.h 307048 2011-01-03 23:53:17Z kalle $ */ ++ ++#ifndef APC_STACK_H ++#define APC_STACK_H ++ ++/* Basic stack datatype */ ++ ++#define T apc_stack_t* ++typedef struct apc_stack_t apc_stack_t; /* opaque stack type */ ++ ++extern T apc_stack_create(int size_hint TSRMLS_DC); ++extern void apc_stack_destroy(T stack TSRMLS_DC); ++extern void apc_stack_clear(T stack); ++extern void apc_stack_push(T stack, void* item TSRMLS_DC); ++extern void* apc_stack_pop(T stack); ++extern void* apc_stack_top(T stack); ++extern void* apc_stack_get(T stack, int n); ++extern int apc_stack_size(T stack); ++ ++#undef T ++#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 ++ */ +diff -Naur a/ext/apc/apc_string.c b/ext/apc/apc_string.c +--- a/ext/apc/apc_string.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_string.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,261 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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: Dmitry Stogov | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 @@ -8667,166 +13662,249 @@ Index: php-5.2.3/ext/apc/apc_sem.c + + */ + -+/* $Id: apc_sem.c,v 3.16 2006/03/12 00:31:45 rasmus Exp $ */ ++/* $Id: apc_string.c 326089 2012-06-11 04:29:57Z rasmus $ */ ++ ++#include "apc.h" ++#include "apc_globals.h" ++#include "apc_php.h" ++#include "apc_lock.h" ++ ++#ifdef ZEND_ENGINE_2_4 ++ ++#ifndef ZTS ++typedef struct _apc_interned_strings_data_t { ++ char *interned_strings_start; ++ char *interned_strings_end; ++ char *interned_strings_top; ++ apc_lck_t lock; ++ HashTable interned_strings; ++} apc_interned_strings_data_t; ++ ++apc_interned_strings_data_t *apc_interned_strings_data = NULL; + -+#include "apc_sem.h" -+#include "apc.h" -+#include "php.h" -+#include -+#include -+#include -+#include -+#include ++#define APCSG(v) (apc_interned_strings_data->v) + -+#if HAVE_SEMUN -+/* we have semun, no need to define */ -+#else -+#undef HAVE_SEMUN -+union semun { -+ int val; /* value for SETVAL */ -+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ -+ unsigned short *array; /* array for GETALL, SETALL */ -+ /* Linux specific part: */ -+ struct seminfo *__buf; /* buffer for IPC_INFO */ -+}; -+#define HAVE_SEMUN 1 -+#endif ++static char *old_interned_strings_start; ++static char *old_interned_strings_end; ++static const char *(*old_new_interned_string)(const char *str, int len, int free_src TSRMLS_DC); ++static void (*old_interned_strings_snapshot)(TSRMLS_D); ++static void (*old_interned_strings_restore)(TSRMLS_D); + -+#ifndef SEM_R -+# define SEM_R 0444 -+#endif -+#ifndef SEM_A -+# define SEM_A 0222 -+#endif ++static const char *apc_dummy_new_interned_string_for_php(const char *str, int len, int free_src TSRMLS_DC) ++{ ++ return str; ++} + -+/* always use SEM_UNDO, otherwise we risk deadlock */ -+#define USE_SEM_UNDO ++static void apc_dummy_interned_strings_snapshot_for_php(TSRMLS_D) ++{ ++} + -+#ifdef USE_SEM_UNDO -+# define UNDO SEM_UNDO -+#else -+# define UNDO 0 ++static void apc_dummy_interned_strings_restore_for_php(TSRMLS_D) ++{ ++} +#endif + -+int apc_sem_create(const char* pathname, int proj, int initval) ++const char *apc_new_interned_string(const char *arKey, int nKeyLength TSRMLS_DC) +{ -+ int semid; -+ int perms; -+ union semun arg; -+ key_t key; ++#ifndef ZTS ++ ulong h; ++ uint nIndex; ++ Bucket *p; ++ ++ if (arKey >= APCSG(interned_strings_start) && arKey < APCSG(interned_strings_end)) { ++ return arKey; ++ } + -+ perms = 0777; ++ h = zend_inline_hash_func(arKey, nKeyLength); ++ nIndex = h & APCSG(interned_strings).nTableMask; + -+ key = IPC_PRIVATE; -+ if (pathname != NULL) { -+ if ((key = ftok(pathname, proj)) < 0) { -+ apc_eprint("apc_sem_create: ftok(%s,%d) failed:", pathname, proj); ++ p = APCSG(interned_strings).arBuckets[nIndex]; ++ while (p != NULL) { ++ if ((p->h == h) && (p->nKeyLength == nKeyLength)) { ++ if (!memcmp(p->arKey, arKey, nKeyLength)) { ++ return p->arKey; ++ } + } ++ p = p->pNext; + } -+ -+ if ((semid = semget(key, 1, IPC_CREAT | IPC_EXCL | perms)) >= 0) { -+ /* sempahore created for the first time, initialize now */ -+ arg.val = initval; -+ if (semctl(semid, 0, SETVAL, arg) < 0) { -+ apc_eprint("apc_sem_create: semctl(%d,...) failed:", semid); -+ } ++ ++ if (APCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength + 1) >= ++ APCSG(interned_strings_end)) { ++ /* no memory */ ++ return NULL; + } -+ else if (errno == EEXIST) { -+ /* sempahore already exists, don't initialize */ -+ if ((semid = semget(key, 1, perms)) < 0) { -+ apc_eprint("apc_sem_create: semget(%u,...) failed:", key); -+ } -+ /* insert here */ ++ ++ p = (Bucket *) APCSG(interned_strings_top); ++ APCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength + 1); ++ ++ p->arKey = (char*)(p+1); ++ memcpy(p->arKey, arKey, nKeyLength); ++ ((char *)p->arKey)[nKeyLength] = '\0'; ++ p->nKeyLength = nKeyLength; ++ p->h = h; ++ p->pData = &p->pDataPtr; ++ p->pDataPtr = p; ++ ++ p->pNext = APCSG(interned_strings).arBuckets[nIndex]; ++ p->pLast = NULL; ++ if (p->pNext) { ++ p->pNext->pLast = p; + } -+ else { -+ apc_eprint("apc_sem_create: semget(%u,...) failed:", key); ++ APCSG(interned_strings).arBuckets[nIndex] = p; ++ ++ p->pListLast = APCSG(interned_strings).pListTail; ++ APCSG(interned_strings).pListTail = p; ++ p->pListNext = NULL; ++ if (p->pListLast != NULL) { ++ p->pListLast->pListNext = p; ++ } ++ if (!APCSG(interned_strings).pListHead) { ++ APCSG(interned_strings).pListHead = p; + } + -+ return semid; -+} ++ APCSG(interned_strings).nNumOfElements++; + -+void apc_sem_destroy(int semid) -+{ -+ /* we expect this call to fail often, so we do not check */ -+ union semun arg; -+ semctl(semid, 0, IPC_RMID, arg); ++ return p->arKey; ++#else ++ return zend_new_interned_string(arKey, nKeyLength, 0 TSRMLS_CC); ++#endif +} + -+void apc_sem_lock(int semid) ++#ifndef ZTS ++static void apc_copy_internal_strings(TSRMLS_D) +{ -+ struct sembuf op; -+ -+ op.sem_num = 0; -+ op.sem_op = -1; -+ op.sem_flg = UNDO; ++ Bucket *p, *q; + -+ if (semop(semid, &op, 1) < 0) { -+ if (errno != EINTR) { -+ apc_eprint("apc_sem_lock: semop(%d) failed:", semid); ++ p = CG(function_table)->pListHead; ++ while (p) { ++ if (p->nKeyLength) { ++ p->arKey = apc_new_interned_string(p->arKey, p->nKeyLength TSRMLS_CC); + } ++ p = p->pListNext; + } -+} + -+void apc_sem_unlock(int semid) -+{ -+ struct sembuf op; ++ p = CG(class_table)->pListHead; ++ while (p) { ++ zend_class_entry *ce = (zend_class_entry*)(p->pDataPtr); + -+ op.sem_num = 0; -+ op.sem_op = 1; -+ op.sem_flg = UNDO; ++ if (p->nKeyLength) { ++ p->arKey = apc_new_interned_string(p->arKey, p->nKeyLength TSRMLS_CC); ++ } + -+ if (semop(semid, &op, 1) < 0) { -+ if (errno != EINTR) { -+ apc_eprint("apc_sem_unlock: semop(%d) failed:", semid); ++ if (ce->name) { ++ ce->name = apc_new_interned_string(ce->name, ce->name_length+1 TSRMLS_CC); ++ } ++ ++ q = ce->properties_info.pListHead; ++ while (q) { ++ zend_property_info *info = (zend_property_info*)(q->pData); ++ ++ if (q->nKeyLength) { ++ q->arKey = apc_new_interned_string(q->arKey, q->nKeyLength TSRMLS_CC); ++ } ++ ++ if (info->name) { ++ info->name = apc_new_interned_string(info->name, info->name_length+1 TSRMLS_CC); ++ } ++ ++ q = q->pListNext; ++ } ++ ++ q = ce->function_table.pListHead; ++ while (q) { ++ if (q->nKeyLength) { ++ q->arKey = apc_new_interned_string(q->arKey, q->nKeyLength TSRMLS_CC); ++ } ++ q = q->pListNext; ++ } ++ ++ q = ce->constants_table.pListHead; ++ while (q) { ++ if (q->nKeyLength) { ++ q->arKey = apc_new_interned_string(q->arKey, q->nKeyLength TSRMLS_CC); ++ } ++ q = q->pListNext; + } ++ ++ p = p->pListNext; ++ } ++ ++ p = EG(zend_constants)->pListHead; ++ while (p) { ++ if (p->nKeyLength) { ++ p->arKey = apc_new_interned_string(p->arKey, p->nKeyLength TSRMLS_CC); ++ } ++ p = p->pListNext; + } +} + -+void apc_sem_wait_for_zero(int semid) ++void apc_interned_strings_init(TSRMLS_D) +{ -+ struct sembuf op; ++ int count = APCG(shm_strings_buffer) / (sizeof(Bucket) + sizeof(Bucket*) * 2); + -+ op.sem_num = 0; -+ op.sem_op = 0; -+ op.sem_flg = UNDO; ++ apc_interned_strings_data = (apc_interned_strings_data_t*) apc_sma_malloc(APCG(shm_strings_buffer) TSRMLS_CC); ++ memset((void *)apc_interned_strings_data, 0, APCG(shm_strings_buffer)); + -+ if (semop(semid, &op, 1) < 0) { -+ if (errno != EINTR) { -+ apc_eprint("apc_sem_waitforzero: semop(%d) failed:", semid); -+ } -+ } ++ CREATE_LOCK(APCSG(lock)); ++ ++ zend_hash_init(&APCSG(interned_strings), count, NULL, NULL, 1); ++ APCSG(interned_strings).nTableMask = APCSG(interned_strings).nTableSize - 1; ++ APCSG(interned_strings).arBuckets = (Bucket**)((char*)apc_interned_strings_data + sizeof(apc_interned_strings_data_t)); ++ ++ APCSG(interned_strings_start) = (char*)APCSG(interned_strings).arBuckets + APCSG(interned_strings).nTableSize * sizeof(Bucket *); ++ APCSG(interned_strings_end) = (char*)apc_interned_strings_data + APCG(shm_strings_buffer); ++ APCSG(interned_strings_top) = APCSG(interned_strings_start); ++ ++ old_interned_strings_start = CG(interned_strings_start); ++ old_interned_strings_end = CG(interned_strings_end); ++ old_new_interned_string = zend_new_interned_string; ++ old_interned_strings_snapshot = zend_interned_strings_snapshot; ++ old_interned_strings_restore = zend_interned_strings_restore; ++ ++ CG(interned_strings_start) = APCSG(interned_strings_start); ++ CG(interned_strings_end) = APCSG(interned_strings_end); ++ zend_new_interned_string = apc_dummy_new_interned_string_for_php; ++ zend_interned_strings_snapshot = apc_dummy_interned_strings_snapshot_for_php; ++ zend_interned_strings_restore = apc_dummy_interned_strings_restore_for_php; ++ ++ apc_copy_internal_strings(TSRMLS_C); +} + -+int apc_sem_get_value(int semid) -+{ -+ union semun arg; -+ unsigned short val[1]; ++void apc_interned_strings_shutdown(TSRMLS_D) ++{ ++ zend_hash_clean(CG(function_table)); ++ zend_hash_clean(CG(class_table)); ++ zend_hash_clean(EG(zend_constants)); + -+ arg.array = val; -+ if (semctl(semid, 0, GETALL, arg) < 0) { -+ apc_eprint("apc_sem_getvalue: semctl(%d,...) failed:", semid); -+ } -+ return val[0]; ++ CG(interned_strings_start) = old_interned_strings_start; ++ CG(interned_strings_end) = old_interned_strings_end; ++ zend_new_interned_string = old_new_interned_string; ++ zend_interned_strings_snapshot = old_interned_strings_snapshot; ++ zend_interned_strings_restore = old_interned_strings_restore; ++ ++ DESTROY_LOCK(APCSG(lock)); +} ++#endif ++ ++#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_sem.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_sem.h 2007-07-30 10:52:17.000000000 -0500 +diff -Naur a/ext/apc/apc_string.h b/ext/apc/apc_string.h +--- a/ext/apc/apc_string.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_string.h 2012-07-20 00:10:35.000000000 +0200 @@ -0,0 +1,51 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -8836,7 +13914,7 @@ Index: php-5.2.3/ext/apc/apc_sem.h + | 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 | ++ | Authors: Dmitry Stogov | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 @@ -8849,19 +13927,19 @@ Index: php-5.2.3/ext/apc/apc_sem.h + + */ + -+/* $Id: apc_sem.h,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */ ++/* $Id: apc_string.h 324145 2012-03-12 11:38:28Z pajoye $ */ + -+#ifndef APC_SEM_H -+#define APC_SEM_H ++#ifndef APC_STRING ++#define APC_STRING + -+/* Wrapper functions for SysV sempahores */ ++#include "apc.h" + -+extern int apc_sem_create(const char* pathname, int proj, int initval); -+extern void apc_sem_destroy(int semid); -+extern void apc_sem_lock(int semid); -+extern void apc_sem_unlock(int semid); -+extern void apc_sem_wait_for_zero(int semid); -+extern int apc_sem_get_value(int semid); ++#ifndef ZTS ++void apc_interned_strings_init(TSRMLS_D); ++void apc_interned_strings_shutdown(TSRMLS_D); ++#endif ++ ++const char *apc_new_interned_string(const char *arKey, int nKeyLength TSRMLS_DC); + +#endif + @@ -8870,19 +13948,18 @@ Index: php-5.2.3/ext/apc/apc_sem.h + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_shm.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_shm.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,111 @@ +diff -Naur a/ext/apc/apc_windows_srwlock_kernel.c b/ext/apc/apc_windows_srwlock_kernel.c +--- a/ext/apc/apc_windows_srwlock_kernel.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_windows_srwlock_kernel.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,133 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -8892,113 +13969,134 @@ Index: php-5.2.3/ext/apc/apc_shm.c + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | Rasmus Lerdorf | ++ | Authors: Pierre Joye | + +----------------------------------------------------------------------+ -+ -+ 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$ */ ++/* ++ These APIs are not actually exposed nor documented. But should work fine ++ from a binary as available since XP without signature changes. ++*/ ++/* ++TODOs: ++non blocking could be possible using the fWait argument (to 0). However ++I'm not sure whether the wait handlers is actually implemented in all ++supported platforms (xp+). could be enabled later once really tested. ++ */ ++/* $Id: $ */ + -+/* $Id: apc_shm.c,v 3.10 2006/05/31 22:24:48 rasmus Exp $ */ -+ -+#include "apc_shm.h" -+#include "apc.h" -+#include -+#ifdef PHP_WIN32 -+/* shm functions are available in TSRM */ -+#include -+#define key_t long -+#else -+#include -+#include -+#include -+#endif ++#include + -+#ifndef SHM_R -+# define SHM_R 0444 /* read permission */ -+#endif -+#ifndef SHM_A -+# define SHM_A 0222 /* write permission */ -+#endif ++#ifdef APC_SRWLOCK_KERNEL ++#include "apc_windows_srwlock_kernel.h" + -+int apc_shm_create(const char* pathname, int proj, int size) ++/* ++For references: ++void WINAPI RtlInitializeResource(LPRTL_RWLOCK rwl); ++void WINAPI RtlDeleteResource(LPRTL_RWLOCK rwl); ++BYTE WINAPI RtlAcquireResourceExclusive(LPRTL_RWLOCK rwl, BYTE fWait); ++BYTE WINAPI RtlAcquireResourceShared(LPRTL_RWLOCK rwl, BYTE fWait); ++void WINAPI RtlReleaseResource(LPRTL_RWLOCK rwl); ++*/ ++typedef void (WINAPI *tRtlInitializeResource)(LPRTL_RWLOCK rwl); ++typedef void (WINAPI *tRtlDeleteResource)(LPRTL_RWLOCK rwl); ++typedef BYTE (WINAPI *tRtlAcquireResourceExclusive)(LPRTL_RWLOCK rwl, BYTE fWait); ++typedef BYTE (WINAPI *tRtlAcquireResourceShared)(LPRTL_RWLOCK rwl, BYTE fWait); ++typedef void (WINAPI *tRtlReleaseResource)(LPRTL_RWLOCK rwl); ++typedef void (WINAPI *tRtlDumpResource)(LPRTL_RWLOCK rwl); ++ ++tRtlInitializeResource pRtlInitializeResource = 0; ++tRtlDeleteResource pRtlDeleteResource = 0; ++tRtlAcquireResourceExclusive pRtlAcquireResourceExclusive = 0; ++tRtlAcquireResourceShared pRtlAcquireResourceShared = 0; ++tRtlReleaseResource pRtlReleaseResource = 0; ++tRtlDumpResource pRtlDumpResource = 0; ++ ++HINSTANCE ntdll; ++ ++void apc_windows_cs_status(apc_windows_cs_rwlock_t *lock ); ++apc_windows_cs_rwlock_t *apc_windows_cs_create(apc_windows_cs_rwlock_t *lock TSRMLS_DC) +{ -+ int shmid; /* shared memory id */ -+ int oflag; /* permissions on shm */ -+ key_t key; /* shm key returned by ftok */ -+ -+ key = IPC_PRIVATE; -+#ifndef PHP_WIN32 -+ /* no ftok yet for win32 */ -+ if (pathname != NULL) { -+ if ((key = ftok(pathname, proj)) < 0) { -+ apc_eprint("apc_shm_create: ftok failed:"); -+ } ++ ntdll = LoadLibrary("ntdll.dll"); ++ if (ntdll == 0) { ++ return NULL; ++ } ++ ++ pRtlInitializeResource = (tRtlInitializeResource) GetProcAddress(ntdll, "RtlInitializeResource"); ++ pRtlDeleteResource = (tRtlDeleteResource) GetProcAddress(ntdll, "RtlDeleteResource"); ++ pRtlAcquireResourceExclusive = (tRtlAcquireResourceExclusive) GetProcAddress(ntdll, "RtlAcquireResourceExclusive"); ++ pRtlAcquireResourceShared = (tRtlAcquireResourceShared) GetProcAddress(ntdll, "RtlAcquireResourceShared"); ++ pRtlReleaseResource = (tRtlReleaseResource) GetProcAddress(ntdll, "RtlReleaseResource"); ++ pRtlDumpResource = (tRtlReleaseResource) GetProcAddress(ntdll, "RtlDumpResource"); ++ if (pRtlInitializeResource == 0 || pRtlDeleteResource == 0 || pRtlAcquireResourceExclusive == 0 || ++ pRtlAcquireResourceShared == 0 || pRtlReleaseResource == 0 || pRtlDumpResource == 0) { ++ return NULL; + } -+#endif ++ pRtlInitializeResource(lock); ++ return lock; ++} + -+ oflag = IPC_CREAT | SHM_R | SHM_A; -+ if ((shmid = shmget(key, size, oflag)) < 0) { -+ apc_eprint("apc_shm_create: shmget(%d, %d, %d) failed: %s. It is possible that the chosen SHM segment size is higher than the operation system allows. Linux has usually a default limit of 32MB per segment.", key, size, oflag, strerror(errno)); ++void apc_windows_cs_destroy(apc_windows_cs_rwlock_t *lock) ++{ ++ __try ++ { ++ pRtlDeleteResource(lock); + } -+ -+ return shmid; ++ __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? ++ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) ++ { ++ /* Ignore exception (resource was freed during shutdown of another thread) */ ++ } ++ FreeLibrary(ntdll); ++ return; +} + -+void apc_shm_destroy(int shmid) ++void apc_windows_cs_lock(apc_windows_cs_rwlock_t *lock TSRMLS_DC) +{ -+ /* we expect this call to fail often, so we do not check */ -+ shmctl(shmid, IPC_RMID, 0); ++ pRtlAcquireResourceExclusive(lock, 1); +} + -+void* apc_shm_attach(int shmid) ++void apc_windows_cs_rdlock(apc_windows_cs_rwlock_t *lock TSRMLS_DC) +{ -+ void* shmaddr; /* the shared memory address */ ++ pRtlAcquireResourceShared(lock, 1); ++} + -+ if ((int)(shmaddr = shmat(shmid, 0, 0)) == -1) { -+ apc_eprint("apc_shm_attach: shmat failed:"); -+ } ++void apc_windows_cs_unlock_rd(apc_windows_cs_rwlock_t *lock TSRMLS_DC) ++{ ++ pRtlReleaseResource(lock); ++} + -+ /* -+ * We set the shmid for removal immediately after attaching to it. The -+ * segment won't disappear until all processes have detached from it. -+ */ -+ apc_shm_destroy(shmid); -+ return shmaddr; ++void apc_windows_cs_unlock_wr(apc_windows_cs_rwlock_t *lock TSRMLS_DC) ++{ ++ pRtlReleaseResource(lock); +} + -+void apc_shm_detach(void* shmaddr) ++/* debugging purposes, output using trace msgs */ ++void apc_windows_cs_status(apc_windows_cs_rwlock_t *lock) +{ -+ if (shmdt(shmaddr) < 0) { -+ apc_eprint("apc_shm_detach: shmdt failed:"); -+ } ++ pRtlDumpResource(lock); ++ return; +} + ++#endif ++ +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_shm.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_shm.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,49 @@ +diff -Naur a/ext/apc/apc_windows_srwlock_kernel.h b/ext/apc/apc_windows_srwlock_kernel.h +--- a/ext/apc/apc_windows_srwlock_kernel.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_windows_srwlock_kernel.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,74 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -9008,30 +14106,55 @@ Index: php-5.2.3/ext/apc/apc_shm.h + | 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 | ++ | Authors: Pierre Joye | + +----------------------------------------------------------------------+ ++ */ ++/* $Id$ */ + -+ 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. ++#ifndef APC_WINDOWS_CS_RWLOCK_H ++#define APC_WINDOWS_CS_RWLOCK_H + -+ All other licensing and usage conditions are those of the PHP Group. ++#include "apc.h" + -+ */ ++#ifdef APC_SRWLOCK_KERNEL + -+/* $Id: apc_shm.h,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */ ++typedef struct _RTL_RWLOCK { ++ RTL_CRITICAL_SECTION rtlCS; + -+#ifndef APC_SHM_H -+#define APC_SHM_H ++ HANDLE hSharedReleaseSemaphore; ++ UINT uSharedWaiters; + -+/* Wrapper functions for unix shared memory */ ++ HANDLE hExclusiveReleaseSemaphore; ++ UINT uExclusiveWaiters; + -+extern int apc_shm_create(const char* name, int proj, int size); -+extern void apc_shm_destroy(int shmid); -+extern void* apc_shm_attach(int shmid); -+extern void apc_shm_detach(void* shmaddr); ++ INT iNumberActive; ++ HANDLE hOwningThreadId; ++ DWORD dwTimeoutBoost; ++ PVOID pDebugInfo; ++} RTL_RWLOCK, *LPRTL_RWLOCK; ++ ++#define apc_windows_cs_rwlock_t RTL_RWLOCK ++ ++struct apc_windows_cs_rwlock_t { ++ CRITICAL_SECTION cs; ++ LONG writers_waiting_count; ++ LONG readers_waiting_count; ++ DWORD active_writers_readers_flag; ++ HANDLE ready_to_read; ++ HANDLE ready_to_write; ++ DWORD reader_races_lost; ++}; ++ ++apc_windows_cs_rwlock_t *apc_windows_cs_create(apc_windows_cs_rwlock_t *lock TSRMLS_DC); ++void apc_windows_cs_destroy(apc_windows_cs_rwlock_t *lock); ++void apc_windows_cs_lock(apc_windows_cs_rwlock_t *lock TSRMLS_DC); ++void apc_windows_cs_rdlock(apc_windows_cs_rwlock_t *lock TSRMLS_DC); ++void apc_windows_cs_unlock_rd(apc_windows_cs_rwlock_t *lock TSRMLS_DC); ++void apc_windows_cs_unlock_wr(apc_windows_cs_rwlock_t *lock TSRMLS_DC); ++# if NONBLOCKING_LOCK_AVAILABLE==1 /* Only in win7/2008 */ ++zend_bool apc_pthreadrwlock_nonblocking_lock(apc_windows_cs_rwlock_t *lock TSRMLS_DC); ++# endif ++#endif + +#endif + @@ -9040,19 +14163,18 @@ Index: php-5.2.3/ext/apc/apc_shm.h + * tab-width: 4 + * c-basic-offset: 4 + * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker ++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ -Index: php-5.2.3/ext/apc/apc_sma.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_sma.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,624 @@ +diff -Naur a/ext/apc/apc_zend.c b/ext/apc/apc_zend.c +--- a/ext/apc/apc_zend.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_zend.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,271 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | ++ | 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 | @@ -9063,5092 +14185,6406 @@ Index: php-5.2.3/ext/apc/apc_sma.c + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | -+ | Rasmus Lerdorf | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 -+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. -+ Future revisions and derivatives of this source code must acknowledge -+ Community Connect Inc. as the original contributor of this module by -+ leaving this note intact in the source code. -+ -+ All other licensing and usage conditions are those of the PHP Group. -+ -+ */ -+ -+/* $Id: apc_sma.c,v 1.63 2007/04/02 09:02:57 gopalv Exp $ */ -+ -+#include "apc_sma.h" -+#include "apc.h" -+#include "apc_globals.h" -+#include "apc_lock.h" -+#include "apc_shm.h" -+#include -+#if APC_MMAP -+void *apc_mmap(char *file_mask, int size); -+void apc_unmap(void* shmaddr, int size); -+#endif ++ 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. + -+/* {{{ locking macros */ -+#define LOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(c); } -+#define RDLOCK(c) { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(c); } -+#define UNLOCK(c) { apc_lck_unlock(c); HANDLE_UNBLOCK_INTERRUPTIONS(); } -+/* }}} */ ++ All other licensing and usage conditions are those of the PHP Group. + -+enum { DEFAULT_NUMSEG=1, DEFAULT_SEGSIZE=30*1024*1024 }; ++ */ + -+static int sma_initialized = 0; /* true if the sma has been initialized */ -+static unsigned int sma_numseg; /* number of shm segments to allow */ -+static size_t sma_segsize; /* size of each shm segment */ -+static int* sma_segments; /* array of shm segment ids */ -+static void** sma_shmaddrs; /* array of shm segment addresses */ -+static int sma_lastseg = 0; /* index of MRU segment */ ++/* $Id: apc_zend.c 307048 2011-01-03 23:53:17Z kalle $ */ + -+typedef struct header_t header_t; -+struct header_t { -+ apc_lck_t sma_lock; /* segment lock, MUST BE ALIGNED for futex locks */ -+ size_t segsize; /* size of entire segment */ -+ size_t avail; /* bytes available (not necessarily contiguous) */ -+ size_t nfoffset; /* start next fit search from this offset */ -+#if ALLOC_DISTRIBUTION -+ size_t adist[30]; -+#endif -+}; ++#include "apc_zend.h" ++#include "apc_globals.h" + ++/* true global */ ++int apc_reserved_offset; + -+/* do not enable for threaded http servers */ -+/* #define __APC_SMA_DEBUG__ 1 */ ++void* apc_php_malloc(size_t n TSRMLS_DC) ++{ ++ return emalloc(n); ++} + -+#ifdef __APC_SMA_DEBUG__ -+/* global counter for identifying blocks -+ * Technically it is possible to do the same -+ * using offsets, but double allocations of the -+ * same offset can happen. */ -+static volatile size_t block_id = 0; -+#endif ++void apc_php_free(void* p TSRMLS_DC) ++{ ++ efree(p); ++} + -+#define APC_SMA_CANARIES 1 ++#ifdef APC_OPCODE_OVERRIDE + -+typedef struct block_t block_t; -+struct block_t { -+ size_t size; /* size of this block */ -+ size_t next; /* offset in segment of next free block */ -+#ifdef APC_SMA_CANARIES -+ size_t canary; /* canary to check for memory overwrites */ -+#endif -+#ifdef __APC_SMA_DEBUG__ -+ size_t id; /* identifier for the memory block */ -+#endif -+}; ++static opcode_handler_t *apc_original_opcode_handlers; ++static opcode_handler_t apc_opcode_handlers[APC_OPCODE_HANDLER_COUNT]; + -+/* The macros BLOCKAT and OFFSET are used for convenience throughout this -+ * module. Both assume the presence of a variable shmaddr that points to the -+ * beginning of the shared memory segment in question. */ ++#define APC_EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset)) + -+#define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset)) -+#define OFFSET(block) ((size_t)(((char*)block) - (char*)shmaddr)) ++#ifdef ZEND_ENGINE_2_4 ++static zval *apc_get_zval_ptr(zend_uchar op_type, znode_op *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC) ++{ ++ *freeval = NULL; ++ ++ switch (op_type) { ++ case IS_CONST: ++ return node->zv; ++ case IS_VAR: ++ return APC_EX_T(node->var).var.ptr; ++ case IS_TMP_VAR: ++ return (*freeval = &APC_EX_T(node->var).tmp_var); ++ case IS_CV: ++ { ++ zval ***ret = &execute_data->CVs[node->var]; + -+/* Canary macros for setting, checking and resetting memory canaries */ -+#ifdef APC_SMA_CANARIES -+ #define SET_CANARY(v) (v)->canary = 0x42424242 -+ #define CHECK_CANARY(v) assert((v)->canary == 0x42424242) -+ #define RESET_CANARY(v) (v)->canary = -42 ++ if (!*ret) { ++ zend_compiled_variable *cv = &EG(active_op_array)->vars[node->var]; ++ ++ if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void**)ret)==FAILURE) { ++ apc_notice("Undefined variable: %s" TSRMLS_CC, cv->name); ++ return &EG(uninitialized_zval); ++ } ++ } ++ return **ret; ++ } ++ case IS_UNUSED: ++ default: ++ return NULL; ++ } ++} +#else -+ #define SET_CANARY(v) -+ #define CHECK_CANARY(v) -+ #define RESET_CANARY(v) -+#endif ++static zval *apc_get_zval_ptr(znode *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC) ++{ ++ *freeval = NULL; ++ ++ switch (node->op_type) { ++ case IS_CONST: ++ return &(node->u.constant); ++ case IS_VAR: ++ return APC_EX_T(node->u.var).var.ptr; ++ case IS_TMP_VAR: ++ return (*freeval = &APC_EX_T(node->u.var).tmp_var); ++#ifdef ZEND_ENGINE_2_1 ++ case IS_CV: ++ { ++ zval ***ret = &execute_data->CVs[node->u.var]; + ++ if (!*ret) { ++ zend_compiled_variable *cv = &EG(active_op_array)->vars[node->u.var]; + -+#ifdef max -+#undef max ++ if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void**)ret)==FAILURE) { ++ apc_notice("Undefined variable: %s" TSRMLS_CC, cv->name); ++ return &EG(uninitialized_zval); ++ } ++ } ++ return **ret; ++ } ++#endif ++ case IS_UNUSED: ++ default: ++ return NULL; ++ } ++} +#endif -+#define max(a, b) ((a) > (b) ? (a) : (b)) -+ -+/* {{{ ALIGNWORD: pad up x, aligned to the system's word boundary */ -+typedef union { void* p; int i; long l; double d; void (*f)(); } apc_word_t; -+#define ALIGNWORD(x) (sizeof(apc_word_t) * (1 + (((x)-1)/sizeof(apc_word_t)))) -+#define MINBLOCKSIZE (ALIGNWORD(1) + ALIGNWORD(sizeof(block_t))) -+/* }}} */ + -+/* {{{ sma_allocate: tries to allocate size bytes in a segment */ -+static int sma_allocate(void* shmaddr, size_t size) ++static int ZEND_FASTCALL apc_op_ZEND_INCLUDE_OR_EVAL(ZEND_OPCODE_HANDLER_ARGS) +{ -+ header_t* header; /* header of shared memory segment */ -+ block_t* prv; /* block prior to working block */ -+ block_t* cur; /* working block in list */ -+ block_t* prvnextfit; /* block before next fit */ -+ size_t realsize; /* actual size of block needed, including header */ -+ size_t last_offset; /* save the last search offset */ -+ int wrapped=0; -+ const size_t block_size = ALIGNWORD(sizeof(struct block_t)); ++ APC_ZEND_OPLINE ++ zval *freeop1 = NULL; ++ zval *inc_filename = NULL, tmp_inc_filename; ++ char realpath[MAXPATHLEN]; ++ php_stream_wrapper *wrapper; ++ char *path_for_open; ++ char *full_path = NULL; ++ int ret = 0; ++ apc_opflags_t* flags = NULL; ++ ++#ifdef ZEND_ENGINE_2_4 ++ if (opline->extended_value != ZEND_INCLUDE_ONCE && ++ opline->extended_value != ZEND_REQUIRE_ONCE) { ++ return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); ++ } ++ ++ inc_filename = apc_get_zval_ptr(opline->op1_type, &opline->op1, &freeop1, execute_data TSRMLS_CC); ++#else ++ if (Z_LVAL(opline->op2.u.constant) != ZEND_INCLUDE_ONCE && ++ Z_LVAL(opline->op2.u.constant) != ZEND_REQUIRE_ONCE) { ++ return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); ++ } + -+ realsize = ALIGNWORD(size + block_size); ++ inc_filename = apc_get_zval_ptr(&opline->op1, &freeop1, execute_data TSRMLS_CC); ++#endif + -+ /* -+ * First, insure that the segment contains at least realsize free bytes, -+ * even if they are not contiguous. -+ */ -+ header = (header_t*) shmaddr; -+ if (header->avail < realsize) { -+ return -1; ++ if (Z_TYPE_P(inc_filename) != IS_STRING) { ++ tmp_inc_filename = *inc_filename; ++ zval_copy_ctor(&tmp_inc_filename); ++ convert_to_string(&tmp_inc_filename); ++ inc_filename = &tmp_inc_filename; + } + -+ prvnextfit = 0; /* initially null (no fit) */ -+ last_offset = 0; ++ wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(inc_filename), &path_for_open, 0 TSRMLS_CC); + -+ /* If we have a next fit offset, start searching from there */ -+ if(header->nfoffset) { -+ prv = BLOCKAT(header->nfoffset); -+ } else { -+ prv = BLOCKAT(sizeof(header_t)); ++ if (wrapper != &php_plain_files_wrapper || !(IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) || (full_path = expand_filepath(path_for_open, realpath TSRMLS_CC)))) { ++ /* Fallback to original handler */ ++ if (inc_filename == &tmp_inc_filename) { ++ zval_dtor(&tmp_inc_filename); ++ } ++ return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } -+ -+ CHECK_CANARY(prv); + -+ while (prv->next != header->nfoffset) { -+ cur = BLOCKAT(prv->next); -+#ifdef __APC_SMA_DEBUG__ -+ CHECK_CANARY(cur); -+#endif -+ /* If it can fit realiszie bytes in cur block, stop searching */ -+ if (cur->size >= realsize) { -+ prvnextfit = prv; -+ break; ++ if (!full_path) { ++ full_path = path_for_open; ++ } ++ if (zend_hash_exists(&EG(included_files), realpath, strlen(realpath) + 1)) { ++#ifdef ZEND_ENGINE_2_4 ++ if (!(opline->result_type & EXT_TYPE_UNUSED)) { ++ ALLOC_INIT_ZVAL(APC_EX_T(opline->result.var).var.ptr); ++ ZVAL_TRUE(APC_EX_T(opline->result.var).var.ptr); ++ } ++#else ++ if (!(opline->result.u.EA.type & EXT_TYPE_UNUSED)) { ++ ALLOC_INIT_ZVAL(APC_EX_T(opline->result.u.var).var.ptr); ++ ZVAL_TRUE(APC_EX_T(opline->result.u.var).var.ptr); + } -+ last_offset = prv->next; -+ prv = cur; -+ if(wrapped && (prv->next >= header->nfoffset)) break; -+ -+ /* Check to see if we need to wrap around and search from the top */ -+ if(header->nfoffset && prv->next == 0) { -+ prv = BLOCKAT(sizeof(header_t)); -+#ifdef __APC_SMA_DEBUG__ -+ CHECK_CANARY(prv); +#endif -+ last_offset = 0; -+ wrapped = 1; -+ } ++ if (inc_filename == &tmp_inc_filename) { ++ zval_dtor(&tmp_inc_filename); ++ } ++ if (freeop1) { ++ zval_dtor(freeop1); ++ } ++ execute_data->opline++; ++ return 0; + } + -+ if (prvnextfit == 0) { -+ header->nfoffset = 0; -+ return -1; ++ if (inc_filename == &tmp_inc_filename) { ++ zval_dtor(&tmp_inc_filename); + } + -+ prv = prvnextfit; -+ cur = BLOCKAT(prv->next); -+ -+ CHECK_CANARY(prv); -+ CHECK_CANARY(cur); -+ -+ if (cur->size == realsize || (cur->size > realsize && cur->size < (realsize + (MINBLOCKSIZE * 2)))) { -+ /* cur is big enough for realsize, but too small to split - unlink it */ -+ prv->next = cur->next; ++ if(apc_reserved_offset != -1) { ++ /* Insanity alert: look into apc_compile.c for why a void** is cast to a apc_opflags_t* */ ++ flags = (apc_opflags_t*) & (execute_data->op_array->reserved[apc_reserved_offset]); + } -+ else { -+ block_t* nxt; /* the new block (chopped part of cur) */ -+ size_t nxtoffset; /* offset of the block currently after cur */ -+ size_t oldsize; /* size of cur before split */ + -+ /* nextfit is too big; split it into two smaller blocks */ -+ nxtoffset = cur->next; -+ oldsize = cur->size; -+ prv->next += realsize; /* skip over newly allocated block */ -+ cur->size = realsize; /* Set the size of this new block */ -+ nxt = BLOCKAT(prv->next); -+ nxt->next = nxtoffset; /* Re-link the shortened block */ -+ nxt->size = oldsize - realsize; /* and fix the size */ -+ SET_CANARY(nxt); -+#ifdef __APC_SMA_DEBUG__ -+ nxt->id = -1; ++ if(flags && flags->deep_copy == 1) { ++ /* Since the op array is a local copy, we can cheat our way through the file inclusion by temporarily ++ * changing the op to a plain require/include, calling its handler and finally restoring the opcode. ++ */ ++#ifdef ZEND_ENGINE_2_4 ++ opline->extended_value = (opline->extended_value == ZEND_INCLUDE_ONCE) ? ZEND_INCLUDE : ZEND_REQUIRE; ++ ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); ++ opline->extended_value = (opline->extended_value == ZEND_INCLUDE) ? ZEND_INCLUDE_ONCE : ZEND_REQUIRE_ONCE; ++#else ++ Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE_ONCE) ? ZEND_INCLUDE : ZEND_REQUIRE; ++ ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); ++ Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE) ? ZEND_INCLUDE_ONCE : ZEND_REQUIRE_ONCE; +#endif ++ } else { ++ ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + -+ /* update the block header */ -+ header->avail -= cur->size; -+#if ALLOC_DISTRIBUTION -+ header->adist[(int)(log(size)/log(2))]++; -+#endif -+ -+ header->nfoffset = last_offset; -+ -+ SET_CANARY(cur); -+#ifdef __APC_SMA_DEBUG__ -+ cur->id = ++block_id; -+ fprintf(stderr, "allocate(realsize=%d,size=%d,id=%d)\n", (int)(size), (int)(cur->size), cur->id); -+#endif -+ -+ return OFFSET(cur) + block_size; ++ return ret; +} -+/* }}} */ + -+/* {{{ sma_deallocate: deallocates the block at the given offset */ -+static int sma_deallocate(void* shmaddr, int offset) ++void apc_zend_init(TSRMLS_D) +{ -+ header_t* header; /* header of shared memory segment */ -+ block_t* cur; /* the new block to insert */ -+ block_t* prv; /* the block before cur */ -+ block_t* nxt; /* the block after cur */ -+ size_t size; /* size of deallocated block */ -+ -+ offset -= ALIGNWORD(sizeof(struct block_t)); -+ assert(offset >= 0); -+ -+ /* find position of new block in free list */ -+ cur = BLOCKAT(offset); -+ prv = BLOCKAT(sizeof(header_t)); -+ -+ CHECK_CANARY(cur); -+ -+#ifdef __APC_SMA_DEBUG__ -+ CHECK_CANARY(prv); -+ fprintf(stderr, "free(%p, size=%d,id=%d)\n", cur, (int)(cur->size), cur->id); -+#endif -+ while (prv->next != 0 && prv->next < offset) { -+ prv = BLOCKAT(prv->next); -+#ifdef __APC_SMA_DEBUG__ -+ CHECK_CANARY(prv); -+#endif -+ } -+ -+ CHECK_CANARY(prv); -+ -+ /* insert new block after prv */ -+ cur->next = prv->next; -+ prv->next = offset; -+ -+#ifdef __APC_SMA_DEBUG__ -+ CHECK_CANARY(cur); -+ cur->id = -1; -+#endif -+ -+ /* update the block header */ -+ header = (header_t*) shmaddr; -+ header->avail += cur->size; -+ size = cur->size; -+ -+ if (((char *)prv) + prv->size == (char *) cur) { -+ /* cur and prv share an edge, combine them */ -+ prv->size += cur->size; -+ prv->next = cur->next; -+ RESET_CANARY(cur); -+ cur = prv; ++ zend_extension dummy_ext; ++ apc_reserved_offset = zend_get_resource_handle(&dummy_ext); ++ assert(apc_reserved_offset == dummy_ext.resource_number); ++ assert(apc_reserved_offset != -1); ++ assert(sizeof(apc_opflags_t) <= sizeof(void*)); ++ if (!APCG(include_once)) { ++ /* If we're not overriding the INCLUDE_OR_EVAL handler, then just skip this malarkey */ ++ return; + } + -+ nxt = BLOCKAT(cur->next); ++ memcpy(apc_opcode_handlers, zend_opcode_handlers, sizeof(apc_opcode_handlers)); + -+ if (((char *)cur) + cur->size == (char *) nxt) { -+ /* cur and nxt shared an edge, combine them */ -+ cur->size += nxt->size; -+ cur->next = nxt->next; -+#ifdef __APC_SMA_DEBUG__ -+ CHECK_CANARY(nxt); -+ nxt->id = -1; /* assert this or set it ? */ ++ /* 5.0 exposes zend_opcode_handlers differently than 5.1 and later */ ++#ifdef ZEND_ENGINE_2_1 ++ apc_original_opcode_handlers = zend_opcode_handlers; ++ zend_opcode_handlers = apc_opcode_handlers; ++#else ++ apc_original_opcode_handlers = apc_opcode_handlers; +#endif -+ RESET_CANARY(nxt); -+ } -+ header->nfoffset = 0; /* Reset the next fit search marker */ + -+ return size; ++ APC_REPLACE_OPCODE(ZEND_INCLUDE_OR_EVAL); +} -+/* }}} */ -+ -+/* {{{ apc_sma_init */ + -+void apc_sma_init(int numseg, int segsize, char *mmap_file_mask) ++void apc_zend_shutdown(TSRMLS_D) +{ -+ int i; -+ -+ if (sma_initialized) { ++ if (!APCG(include_once)) { ++ /* Nothing changed, nothing to restore */ + return; + } -+ sma_initialized = 1; + -+#if APC_MMAP -+ /* -+ * I don't think multiple anonymous mmaps makes any sense -+ * so force sma_numseg to 1 in this case -+ */ -+ if(!mmap_file_mask || -+ (mmap_file_mask && !strlen(mmap_file_mask)) || -+ (mmap_file_mask && !strcmp(mmap_file_mask, "/dev/zero"))) { -+ sma_numseg = 1; -+ } else { -+ sma_numseg = numseg > 0 ? numseg : DEFAULT_NUMSEG; -+ } ++#ifdef ZEND_ENGINE_2_1 ++ zend_opcode_handlers = apc_original_opcode_handlers; +#else -+ sma_numseg = numseg > 0 ? numseg : DEFAULT_NUMSEG; ++ memcpy(zend_opcode_handlers, apc_original_opcode_handlers, sizeof(apc_opcode_handlers)); +#endif ++} ++ ++#else /* Opcode Overrides unavailable */ ++ ++void apc_zend_init(TSRMLS_D) { } ++void apc_zend_shutdown(TSRMLS_D) { } ++ ++#endif /* APC_OPCODE_OVERRIDE */ ++ ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/apc_zend.h b/ext/apc/apc_zend.h +--- a/ext/apc/apc_zend.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/apc_zend.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,191 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ +----------------------------------------------------------------------+ + -+ sma_segsize = segsize > 0 ? segsize : DEFAULT_SEGSIZE; ++ 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. + -+ sma_segments = (int*) apc_emalloc(sma_numseg*sizeof(int)); -+ sma_shmaddrs = (void**) apc_emalloc(sma_numseg*sizeof(void*)); -+ -+ for (i = 0; i < sma_numseg; i++) { -+ header_t* header; -+ block_t* block; -+ void* shmaddr; ++ All other licensing and usage conditions are those of the PHP Group. + -+#if APC_MMAP -+ sma_segments[i] = sma_segsize; -+ sma_shmaddrs[i] = apc_mmap(mmap_file_mask, sma_segsize); -+ if(sma_numseg != 1) memcpy(&mmap_file_mask[strlen(mmap_file_mask)-6], "XXXXXX", 6); -+#else -+ sma_segments[i] = apc_shm_create(NULL, i, sma_segsize); -+ sma_shmaddrs[i] = apc_shm_attach(sma_segments[i]); -+#endif -+ shmaddr = sma_shmaddrs[i]; -+ -+ header = (header_t*) shmaddr; -+ apc_lck_create(NULL, 0, 1, header->sma_lock); -+ header->segsize = sma_segsize; -+ header->avail = sma_segsize - sizeof(header_t) - sizeof(block_t) - -+ ALIGNWORD(sizeof(int)); -+ header->nfoffset = 0; -+#if ALLOC_DISTRIBUTION -+ { -+ int j; -+ for(j=0; j<30; j++) header->adist[j] = 0; -+ } -+#endif -+ block = BLOCKAT(sizeof(header_t)); -+ block->size = 0; -+ block->next = sizeof(header_t) + sizeof(block_t); -+ SET_CANARY(block); -+#ifdef __APC_SMA_DEBUG__ -+ block->id = -1; -+#endif -+ block = BLOCKAT(block->next); -+ block->size = header->avail; -+ block->next = 0; -+ SET_CANARY(block); -+#ifdef __APC_SMA_DEBUG__ -+ block->id = -1; ++ */ ++ ++/* $Id: apc_zend.h 326712 2012-07-19 21:33:27Z rasmus $ */ ++ ++#ifndef APC_ZEND_H ++#define APC_ZEND_H ++ ++/* Utilities for interfacing with the zend engine */ ++ ++#include "apc.h" ++#include "apc_php.h" ++ ++#ifndef Z_REFCOUNT_P ++#define Z_REFCOUNT_P(pz) (pz)->refcount ++#define Z_REFCOUNT_PP(ppz) Z_REFCOUNT_P(*(ppz)) +#endif -+ } -+} -+/* }}} */ + -+/* {{{ apc_sma_cleanup */ -+void apc_sma_cleanup() -+{ -+ int i; ++#ifndef Z_SET_REFCOUNT_P ++#define Z_SET_REFCOUNT_P(pz, rc) (pz)->refcount = rc ++#define Z_SET_REFCOUNT_PP(ppz, rc) Z_SET_REFCOUNT_P(*(ppz), rc) ++#endif + -+ assert(sma_initialized); ++#ifndef Z_ADDREF_P ++#define Z_ADDREF_P(pz) (pz)->refcount++ ++#define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz)) ++#endif + -+ for (i = 0; i < sma_numseg; i++) { -+ apc_lck_destroy(((header_t*)sma_shmaddrs[i])->sma_lock); -+#if APC_MMAP -+ apc_unmap(sma_shmaddrs[i], sma_segments[i]); -+#else -+ apc_shm_detach(sma_shmaddrs[i]); ++#ifndef Z_DELREF_P ++#define Z_DELREF_P(pz) (pz)->refcount-- ++#define Z_DELREF_PP(ppz) Z_DELREF_P(*(ppz)) +#endif -+ } -+ sma_initialized = 0; -+ apc_efree(sma_segments); -+ apc_efree(sma_shmaddrs); -+} -+/* }}} */ + -+/* {{{ apc_sma_malloc */ -+void* apc_sma_malloc(size_t n) -+{ -+ int off; -+ int i; ++#ifndef Z_ISREF_P ++#define Z_ISREF_P(pz) (pz)->is_ref ++#define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz)) ++#endif + -+ TSRMLS_FETCH(); -+ assert(sma_initialized); -+ LOCK(((header_t*)sma_shmaddrs[sma_lastseg])->sma_lock); ++#ifndef Z_SET_ISREF_P ++#define Z_SET_ISREF_P(pz) (pz)->is_ref = 1 ++#define Z_SET_ISREF_PP(ppz) Z_SET_ISREF_P(*(ppz)) ++#endif + -+ off = sma_allocate(sma_shmaddrs[sma_lastseg], n); -+ if (off != -1) { -+ void* p = (void *)(((char *)(sma_shmaddrs[sma_lastseg])) + off); -+ if (APCG(mem_size_ptr) != NULL) { *(APCG(mem_size_ptr)) += n; } -+ UNLOCK(((header_t*)sma_shmaddrs[sma_lastseg])->sma_lock); -+ return p; -+ } -+ UNLOCK(((header_t*)sma_shmaddrs[sma_lastseg])->sma_lock); ++#ifndef Z_UNSET_ISREF_P ++#define Z_UNSET_ISREF_P(pz) (pz)->is_ref = 0 ++#define Z_UNSET_ISREF_PP(ppz) Z_UNSET_ISREF_P(*(ppz)) ++#endif + -+ for (i = 0; i < sma_numseg; i++) { -+ LOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ if (i == sma_lastseg) { -+ continue; -+ } -+ off = sma_allocate(sma_shmaddrs[i], n); -+ if (off != -1) { -+ void* p = (void *)(((char *)(sma_shmaddrs[i])) + off); -+ if (APCG(mem_size_ptr) != NULL) { *(APCG(mem_size_ptr)) += n; } -+ UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ sma_lastseg = i; -+ return p; -+ } -+ UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ } ++#ifndef Z_SET_ISREF_TO_P ++#define Z_SET_ISREF_TO_P(pz, isref) (pz)->is_ref = isref ++#define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref) ++#endif + -+ return NULL; -+} -+/* }}} */ + -+/* {{{ apc_sma_realloc */ -+void* apc_sma_realloc(void *p, size_t n) -+{ -+ apc_sma_free(p); -+ return apc_sma_malloc(n); -+} -+/* }}} */ ++extern void* apc_php_malloc(size_t n TSRMLS_DC); ++extern void apc_php_free(void* p TSRMLS_DC); + -+/* {{{ apc_sma_strdup */ -+char* apc_sma_strdup(const char* s) -+{ -+ void* q; -+ int len; ++extern void apc_zend_init(TSRMLS_D); ++extern void apc_zend_shutdown(TSRMLS_D); + -+ if(!s) return NULL; + -+ len = strlen(s)+1; -+ q = apc_sma_malloc(len); -+ if(!q) return NULL; -+ memcpy(q, s, len); -+ return q; -+} -+/* }}} */ ++/* offset for apc info in op_array->reserved */ ++extern int apc_reserved_offset; + -+/* {{{ apc_sma_free */ -+void apc_sma_free(void* p) -+{ -+ int i; -+ size_t offset; -+ size_t d_size; -+ TSRMLS_FETCH(); ++#ifndef ZEND_VM_KIND_CALL /* Not currently defined by any ZE version */ ++# define ZEND_VM_KIND_CALL 1 ++#endif + -+ if (p == NULL) { -+ return; -+ } ++#ifndef ZEND_VM_KIND /* Indicates PHP < 5.1 */ ++# define ZEND_VM_KIND ZEND_VM_KIND_CALL ++#endif + -+ assert(sma_initialized); ++#if defined(ZEND_ENGINE_2) && (ZEND_VM_KIND == ZEND_VM_KIND_CALL) ++# define APC_OPCODE_OVERRIDE ++#endif + -+ for (i = 0; i < sma_numseg; i++) { -+ LOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ offset = (size_t)((char *)p - (char *)(sma_shmaddrs[i])); -+ if (p >= sma_shmaddrs[i] && offset < sma_segsize) { -+ d_size = sma_deallocate(sma_shmaddrs[i], offset); -+ if (APCG(mem_size_ptr) != NULL) { *(APCG(mem_size_ptr)) -= d_size; } -+ UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ return; -+ } -+ UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ } ++#ifdef APC_OPCODE_OVERRIDE + -+ apc_eprint("apc_sma_free: could not locate address %p", p); ++#ifdef ZEND_ENGINE_2_1 ++/* Taken from Zend/zend_vm_execute.h */ ++#define _CONST_CODE 0 ++#define _TMP_CODE 1 ++#define _VAR_CODE 2 ++#define _UNUSED_CODE 3 ++#define _CV_CODE 4 ++static inline int _apc_opcode_handler_decode(zend_op *opline) ++{ ++ static const int apc_vm_decode[] = { ++ _UNUSED_CODE, /* 0 */ ++ _CONST_CODE, /* 1 = IS_CONST */ ++ _TMP_CODE, /* 2 = IS_TMP_VAR */ ++ _UNUSED_CODE, /* 3 */ ++ _VAR_CODE, /* 4 = IS_VAR */ ++ _UNUSED_CODE, /* 5 */ ++ _UNUSED_CODE, /* 6 */ ++ _UNUSED_CODE, /* 7 */ ++ _UNUSED_CODE, /* 8 = IS_UNUSED */ ++ _UNUSED_CODE, /* 9 */ ++ _UNUSED_CODE, /* 10 */ ++ _UNUSED_CODE, /* 11 */ ++ _UNUSED_CODE, /* 12 */ ++ _UNUSED_CODE, /* 13 */ ++ _UNUSED_CODE, /* 14 */ ++ _UNUSED_CODE, /* 15 */ ++ _CV_CODE /* 16 = IS_CV */ ++ }; ++#ifdef ZEND_ENGINE_2_4 ++ return (opline->opcode * 25) + (apc_vm_decode[opline->op1_type] * 5) + apc_vm_decode[opline->op2_type]; ++#else ++ return (opline->opcode * 25) + (apc_vm_decode[opline->op1.op_type] * 5) + apc_vm_decode[opline->op2.op_type]; ++#endif +} -+/* }}} */ + -+/* {{{ apc_sma_info */ -+apc_sma_info_t* apc_sma_info(zend_bool limited) -+{ -+ apc_sma_info_t* info; -+ apc_sma_link_t** link; -+ int i; -+ char* shmaddr; -+ block_t* prv; -+ -+ if (!sma_initialized) { -+ return NULL; -+ } ++# define APC_ZEND_OPLINE zend_op *opline = execute_data->opline; ++# define APC_OPCODE_HANDLER_DECODE(opline) _apc_opcode_handler_decode(opline) ++# if PHP_MAJOR_VERSION >= 6 ++# define APC_OPCODE_HANDLER_COUNT ((25 * 152) + 1) ++# elif defined(ZEND_ENGINE_2_4) ++# define APC_OPCODE_HANDLER_COUNT ((25 * 159) + 1) /* 5 new opcodes in 5.4 - qm_assign_var, jmp_set_var, separate, bind_trais, add_trait */ ++# elif PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 3 ++# define APC_OPCODE_HANDLER_COUNT ((25 * 154) + 1) /* 3 new opcodes in 5.3 - unused, lambda, jmp_set */ ++# else ++# define APC_OPCODE_HANDLER_COUNT ((25 * 151) + 1) ++# endif ++# define APC_REPLACE_OPCODE(opname) { int i; for(i = 0; i < 25; i++) if (zend_opcode_handlers[(opname*25) + i]) zend_opcode_handlers[(opname*25) + i] = apc_op_##opname; } + -+ info = (apc_sma_info_t*) apc_emalloc(sizeof(apc_sma_info_t)); -+ info->num_seg = sma_numseg; -+ info->seg_size = sma_segsize - sizeof(header_t) - sizeof(block_t) - ALIGNWORD(sizeof(int)); ++#else /* ZE2.0 */ ++# define APC_ZEND_ONLINE ++# define APC_OPCODE_HANDLER_DECODE(opline) (opline->opcode) ++# define APC_OPCODE_HANDLER_COUNT 512 ++# define APC_REPLACE_OPCODE(opname) zend_opcode_handlers[opname] = apc_op_##opname; ++#endif + -+ info->list = apc_emalloc(info->num_seg * sizeof(apc_sma_link_t*)); -+ for (i = 0; i < sma_numseg; i++) { -+ info->list[i] = NULL; -+ } ++#ifndef ZEND_FASTCALL /* Added in ZE2.3.0 */ ++#define ZEND_FASTCALL ++#endif + -+ if(limited) return info; ++/* Added in ZE2.3.0 */ ++#ifndef zend_parse_parameters_none ++# define zend_parse_parameters_none() zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") ++#endif + -+ /* For each segment */ -+ for (i = 0; i < sma_numseg; i++) { -+ RDLOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ shmaddr = sma_shmaddrs[i]; -+ prv = BLOCKAT(sizeof(header_t)); + -+ link = &info->list[i]; ++#endif /* APC_OPCODE_OVERRIDE */ + -+ /* For each block in this segment */ -+ while (prv->next != 0) { -+ block_t* cur = BLOCKAT(prv->next); -+#ifdef __APC_SMA_DEBUG__ -+ CHECK_CANARY(cur); ++#ifdef ZEND_ENGINE_2_4 ++# define ZEND_CE_FILENAME(ce) (ce)->info.user.filename ++# define ZEND_CE_DOC_COMMENT(ce) (ce)->info.user.doc_comment ++# define ZEND_CE_DOC_COMMENT_LEN(ce) (ce)->info.user.doc_comment_len ++# define ZEND_CE_BUILTIN_FUNCTIONS(ce) (ce)->info.internal.builtin_functions ++#else ++# define ZEND_CE_FILENAME(ce) (ce)->filename ++# define ZEND_CE_DOC_COMMENT(ce) (ce)->doc_comment ++# define ZEND_CE_DOC_COMMENT_LEN(ce) (ce)->doc_comment_len ++# define ZEND_CE_BUILTIN_FUNCTIONS(ce) (ce)->builtin_functions +#endif + -+ *link = apc_emalloc(sizeof(apc_sma_link_t)); -+ (*link)->size = cur->size; -+ (*link)->offset = prv->next; -+ (*link)->next = NULL; -+ link = &(*link)->next; ++#endif /* APC_ZEND_H */ + -+ prv = cur; -+ } -+ UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock); -+ } ++/* ++ * 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 ++ */ +diff -Naur a/ext/apc/CHANGELOG b/ext/apc/CHANGELOG +--- a/ext/apc/CHANGELOG 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/CHANGELOG 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,249 @@ ++ ++3.1.2 : 2008-12-12 ++ ++- pecl package.xml/build fixes (bjori) ++ ++3.1.1 : 2008-12-12 ++ ++- PHP4 compatibilty break ++- apc_pool allocator (Gopal) ++- doubly-linked sma allocator (Shire) ++- php 5.3 gc compatibility (Gopal) ++- APCIterator for easy access (Shire) ++- apc_delete_file (Shire) ++- apc_inc/apc_dec/apc_cas functions (Shire) ++- apc.canonicalize (Gopal) ++- apc.preload_path (Gopal) ++- apc.rfc1867_ttl (Shire) ++- apc.file_md5 (Shire) ++- consolidate locking macros (Shire) ++- remove futex/TSRM locks (Shire) ++- non-blocking semaphore locks (Shire) ++- zval* object rework (Gopal) ++ ++3.0.19: 2008-05-14 ++- Safe-mode and fast-cgi fixes ++- Fix double-free of builtin_functions ++- php 5.3 fixes ++ ++3.0.18: 2008-03-29 ++- Revert apc_expunge_cb bug-fix ++- Misc memleaks ++ ++3.0.17: 2008-03-26 ++- Crash fixes ++- Fix apc_add() cache expunge bug (Rasmus) ++- Added parameter to apc_fetch to determine success/failure when fetching booleans (shire) ++- Fix misc. memleaks (shire) ++ ++3.0.16: 2007-12-26 ++- Fix for longstanding cache-full crash (Christian Seiler) ++ http://news.php.net/php.pecl.dev/4951 for the details ++- Added optional shm unmap on a fatal signal feature (Lucas Nealan) ++- Added PTHREAD_MUTEX_ADAPTIVE_NP option pthread locks (Paul Saab) ++- Minor cleanups (Lucas Nealan) ++- Added configure option to enable apc_cache_info('filehits') (Shire) ++ ++3.0.15: 2007-10-18 ++- Eliminate a per-request time() syscall (Rasmus) ++- Added rfc1867 prefix, name, and freq ini options (Shire) ++- Allow deletion of individual user cache entries via apc.php (Sara) ++- Fix overzealous cleanup during RSHUTDOWN (Gopal) ++- Fix memory alignment and locking issues (Gopal) ++- Make apc_compile insert/replace entries (Shire) ++- Make mixed inheritance recompile & cache afresh (Gopal) ++- Make nostat mode search include_path for canonicalization (Gopal) ++- ZTS & other compile fixes (Gopal, Edin, Shire) ++ ++3.0.14: 2007-03-21 ++- Build fix (Shire) ++- Don't hook the upload hook if APC is disabled (Rasmus) ++- Local shadow cache support (Gopal) ++- Avoid uneccessary loops over op_arrays for "known" auto-globals (Gopal) ++- Fix apc_add() to overwrite timed out user entries (Rasmus) ++- Fix double inclusion of files with conditional classes in php4 (Gopal) ++- Allocator fixes to reduce fragmentation (Gopal) + -+ return info; -+} -+/* }}} */ ++3.0.13: 2007-02-24 ++- File upload progress (Rasmus) ++- Pthread mutex and spin locks (Shire) ++- Recursive zval support for apc_fetch/_store (Shire, Gopal) ++- apc.stat_ctime flag for ctime checks (Rasmus) ++- Multiple key fetches with apc_fetch (Shire) ++- Canary checks for shm memory deallocation (Gopal) ++- Add hooks for external optimizer (Shire) ++- Obsolete and remove apc optimizer (Gopal) ++- APC info changes - cache insert rate, hit and miss rates (Shire) ++- Fix apc_load_constants (Gopal) ++- Rewrite dump opcode code to use vld (Gopal) ++- Use apc_[ewn]print functions for error reporting (Shire) ++- Auto global fixes and refactoring (Gopal, Shire) ++- Fix memory leaks in object serialization (Ilia) ++- Memory cleanup code for destructor order (Gopal) ++- Win32 build fixes (Ilia, Wez) ++- ZTS and Php 4 build fixes (Bjori) ++- Add apc_add() function (Rasmus) ++- Add optional limited flag to apc_sma_info() (Rasmus) + -+/* {{{ apc_sma_free_info */ -+void apc_sma_free_info(apc_sma_info_t* info) -+{ -+ int i; ++3.0.12p2: 2006-09-05 ++- Package version up + -+ for (i = 0; i < info->num_seg; i++) { -+ apc_sma_link_t* p = info->list[i]; -+ while (p) { -+ apc_sma_link_t* q = p; -+ p = p->next; -+ apc_efree(q); -+ } -+ } -+ apc_efree(info->list); -+ apc_efree(info); -+} -+/* }}} */ ++3.0,12p1: 2006-09-05 ++- PHP4 build fixes + -+/* {{{ apc_sma_get_avail_mem */ -+int apc_sma_get_avail_mem() -+{ -+ int avail_mem = 0; -+ int i; -+ -+ for (i = 0; i < sma_numseg; i++) { -+ header_t* header = (header_t*) sma_shmaddrs[i]; -+ avail_mem += header->avail; -+ } -+ return avail_mem; -+} -+/* }}} */ ++3.0.12: 2006-09-05 ++- PHP 5.2 compatibility (Gopal) ++- TSRM fixes (Gopal) ++- Add extra flags to op_array->reserved to improve op array ++ processing code (Gopal) ++- Fix crashes in optimizer and cli mode (Ilia) ++- Optimizer fixes for PHP5 (Ilia, Gopal) ++- Allow multiple inclusions of a file with a dynamic class (Gopal) ++- Php 4 function table and properties fixes (Gopal) ++- Fix memory leaks in apc_cache_info (Gopal) ++ ++3.0.11: 2006-08-16 ++- Made --enable-apc-mmap the default compile option (for real this time) ++- Add an optional flag to apc_cache_info() and some apc.php tweaks to make it ++ only fetch header information to make it useful when you have tens of ++ thousands of entries. (Brian Shire) ++- 64-bit fixes (George) ++- Don't mix Full Path and Inode keys (George) ++- Override ZEND_INCLUDE_OR_EVAL opcode (when possible) to speed up use of ++ require_once() and include_once() statements. (Sara) ++- Add a non-blocking write_lock for cache inserts. This is a better approach ++ to prevent cache slams and deprecates the slam_defense setting. (Rasmus) ++- A bit of work on the optimizer. (Sara) ++- Various memory issues resolved. (Gopal) ++ ++3.0.10: 2006-03-11 ++- Add apc.stat ini flag which defaults to 1. If set to 0, the main script and any fullpath ++ includes will not be stat'ed for any changes. You will have to restart the server if you ++ change anything. This mode increases performance quite a bit, especially if you have a ++ lot of includes. + -+#if ALLOC_DISTRIBUTION -+size_t *apc_sma_get_alloc_distribution(void) { -+ header_t* header = (header_t*) sma_shmaddrs[0]; -+ return header->adist; -+} -+#endif ++- Get rid of the lock safety net hack I added in 3.0.9. It seems to cause more problems ++ than it solves. I'll need to revisit locking and signal handling at some point soon. + -+#if 0 -+/* {{{ apc_sma_check_integrity */ -+void apc_sma_check_integrity() -+{ -+ int i; ++3.0.9: 2006-03-04 ++- Eliminate rand() call when slam_defense is not set (Rasmus) ++- Fix for __isset problem (Gopal) ++- Rewrite allocator from a "best fit" to a "next fit" algorithm (Rasmus) ++- Added a Cache Full counter so we have an idea how many times the segment has filled up causing an expunge (Rasmus) ++- Report back the correct number of available bytes in the segment instead of the allocated bytes. (Rasmus) ++- Add cache busy flag which is set when an expunge is underway (Rasmus) ++- Add automatic serialization of objects in apc_store() (Marcus) ++- 64-bit .ini flag fix (Rasmus) ++- Static members fix (Gopal) ++- sma_cleanup() mem leak fix (Rasmus) ++- Fix for http://pecl.php.net/bugs/5311 (Rasmus) ++- Fix autoglobals JIT bug (Gopal) ++- Fix instance bug (Gopal) ++- Add a lock cleanup safety net to request shutdown (Rasmus) ++- Fix apc.slam_defense edge-case bug (Rasmus) ++- User entry memory usage tracking support (Ilia) ++- Allow keys used in apc_store/apc_fetch/apc_delete to be binary safe and prevent conflicts between keys that are found at the start of other keys. (Ilia) + -+ /* For each segment */ -+ for (i = 0; i < sma_numseg; i++) { -+ char* shmaddr = sma_shmaddrs[i]; -+ header_t* header = (header_t*) shmaddr; -+ block_t* prv = BLOCKAT(sizeof(header_t)); -+ int avail = 0; ++3.0.8: 2005-08-24 ++Fix invalid free in globals destructor introduced in 3.0.7 (Rasmus) ++Cache corruption fix in cache-full cleanup code (Gopal) + -+ /* For each block in this segment */ -+ while (prv->next != 0) { -+ block_t* cur = BLOCKAT(prv->next); -+ avail += cur->size; -+ prv = cur; -+ } ++3.0.7: 2005-08-16 ++- Fix to apc.php to show final segment in frag chart. (Ilia) ++- A couple of win32 fixes. (Frank) ++- Add apc.enable_cli ini directive. (Rasmus) ++- Add test cases. (Marcus) ++- Fix apc_define_constants() bug - http://pecl.php.net/bugs/5084 (Rasmus) ++- Simplify user cache handling by removing the user_cache_stack (Rasmus) ++- Fix apc_fetch() memory corruption (Andrei,Rasmus) ++- Added apc.max_file_size INI setting that allows exclusion of large files from being cached. Default file size limit, 1 megabyte. (Ilia) + -+ assert(avail == header->avail); -+ } -+} -+/* }}} */ -+#endif ++3.0.6: 2005-07-30 ++- Added apc.php to package.xml file. ++- Track per-entry memory usage. (Val) ++- Various apc.php fixes and enhancements. (Ralf, Ilia, Rasmus) ++- fcntl locking robustness fixes. (Rasmus) ++- Shared read-locks where possible. (Rasmus) ++- Added file_update_protection configuration parameter. (Rasmus) ++- Windows ZTS fixes (Frank) + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_sma.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_sma.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,82 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ +----------------------------------------------------------------------+ ++3.0.5: 2005-07-27 ++- Make it easier for sapis that only populate file_handle->filename to use APC. (Rasmus) ++- Support extensions such as bcompiler that need to hook into compile_file. (Val) ++- Ralf Becker's apcgui code has now become the default apc.php status page. (Ralf, Rasmus, Ilia) ++- Segfault in cache cleanup code (Ilia, Rasmus) + -+ 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. ++3.0.4: 2005-07-18 ++- Add win32 support (Edin ) ++- Add --with-apxs switch to work around problem when loading APC into Apache binary compiled with LFS switches (Rasmus) ++- A couple of other minor fixes + -+ All other licensing and usage conditions are those of the PHP Group. ++3.0.3: 2005-07-05 ++- Fix compile problem against PHP 5.0.x + -+ */ ++3.0.2: 2005-07-05 ++- Better shm error message + -+/* $Id: apc_sma.h,v 1.16 2007/02/24 11:59:40 rasmus Exp $ */ ++3.0.1: 2005-07-05 ++- PHP4 build fix + -+#ifndef APC_SMA_H -+#define APC_SMA_H ++3.0: 2005-06-23 ++- PHP 5.1 support (Arun, Gopal, Rasmus) ++- Major Inheritance bug fix (Arun, Gopal) + -+#define ALLOC_DISTRIBUTION 0 ++2.0: 2003-02-10 ++- ground-up rewrite sharing none of the original source code (djc) + -+#include "apc.h" ++1.0.10: ++- merge mmap / shm code to be in one file, module supports both modes now [mpb 2001-05-15] ++- added apc.mode config parameter [mpb 2001-05-15] NOTE: You'll have to add ++ this parameter to your php.ini file to activate apc shm or mmap caching ++- generic source cleanup (missing includes, PATH_MAX usage etc) [mpb ++ 2001-05-15] ++- fixed: realpath return result checking in generate_key [mpb 2001-05-15] ++- updated: gui updated (extras/apc_gui-1.0.2.tar.gz) ++- experminental 'fast' cache-retrieval [djc 2001-05-20] ++- fixed regex support [gws 2001-05-16] ++- enhanced reader-writer lock support [rg 2001-05-07] + -+/* Simple shared memory allocator */ ++1.0.9: ++- fixed (?) memory alignment bug on 64 bit archiecures ++- added many cache visibiliy functions ++- added opional fcntl locks under shm version ++- numerous bug fixes + -+extern void apc_sma_init(int numseg, int segsize, char *mmap_file_mask); -+extern void apc_sma_cleanup(); -+extern void* apc_sma_malloc(size_t size); -+extern void* apc_sma_realloc(void* p, size_t size); -+extern char* apc_sma_strdup(const char *s); -+extern void apc_sma_free(void* p); -+#if ALLOC_DISTRIBUTION -+extern size_t *apc_sma_get_alloc_distribution(); -+#endif ++1.0.8: ++- added ability to detect and decompile compiled files placed as 'source' ++ [gws,dw 2001-01-30] ++- fixed apc_rstat bug [gws 2001-01-29] ++- added hack to support included urls [gws 2001-01-30] ++- fixed apc_cache_index [mb 2001-01-31] ++- added multiple regex support [gs 2001-02-03] ++- added apc_cache_info [mb,gs 2001-02-03] + -+/* {{{ struct definition: apc_sma_link_t */ -+typedef struct apc_sma_link_t apc_sma_link_t; -+struct apc_sma_link_t { -+ int size; /* size of this free block */ -+ int offset; /* offset in segment of this block */ -+ apc_sma_link_t* next; /* link to next free block */ -+}; -+/* }}} */ ++1.0.7: ++- partially fixed for Solaris [gws 2001-01-29] ++- fixed mtime support for relative includes [gws 2001-01-29] ++- code cleanup [yg,ta,gws 2001-01-29] + -+/* {{{ struct definition: apc_sma_info_t */ -+typedef struct apc_sma_info_t apc_sma_info_t; -+struct apc_sma_info_t { -+ int num_seg; /* number of shared memory segments */ -+ int seg_size; /* size of each shared memory segment */ -+ apc_sma_link_t** list; /* there is one list per segment */ -+}; -+/* }}} */ ++1.0.6: ++- support for mtime in mmap [yg,gws 2001-01-27] ++- fixed indexed-array initialization bug [djc,gws 2001-01-27] + -+extern apc_sma_info_t* apc_sma_info(zend_bool limited); -+extern void apc_sma_free_info(apc_sma_info_t* info); ++1.0.5: ++- support for relative include paths [djc,gws 2001-01-19] ++- class member array support fixed [djc 2001-01-18] ++- added apc_cache_index [gws 2001-01-18] + -+extern int apc_sma_get_avail_mem(); -+extern void apc_sma_check_integrity(); ++1.0.4: ++- support for class hierarchies greater than two levels deep [djc 2001-01-17] + -+#endif ++1.0.3: ++- fixed support for class inheritance [djc 2001-01-16] + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_spin.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_spin.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,65 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2007 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: Brian Shire | -+ +----------------------------------------------------------------------+ ++1.0.2: ++- support for inherited classes [gws 2001-01-15] ++- support for intialization of class variables and objects [gws 2001-01-13] + -+ */ ++1.0.1: ++- added optional file modification time check [djc 2001-01-12] +diff -Naur a/ext/apc/config.m4 b/ext/apc/config.m4 +--- a/ext/apc/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/config.m4 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,404 @@ ++dnl ++dnl $Id: config.m4 326700 2012-07-19 11:56:57Z ab $ ++dnl + -+/* $Id: apc_spin.c,v 3.1 2007/01/29 07:39:02 shire Exp $ */ ++PHP_ARG_ENABLE(apc, whether to enable APC support, ++[ --enable-apc Enable APC support]) + -+#include "apc_spin.h" ++AC_ARG_ENABLE(apc-debug, ++[ --enable-apc-debug Enable APC debugging], ++[ ++ PHP_APC_DEBUG=$enableval ++], ++[ ++ PHP_APC_DEBUG=no ++]) + -+#ifdef APC_SPIN_LOCKS ++AC_MSG_CHECKING(whether we should enable cache request file info) ++AC_ARG_ENABLE(apc-filehits, ++[ --enable-apc-filehits Enable per request file info about files used from the APC cache (ie: apc_cache_info('filehits')) ], ++[ ++ PHP_APC_FILEHITS=$enableval ++ AC_MSG_RESULT($enableval) ++], ++[ ++ PHP_APC_FILEHITS=no ++ AC_MSG_RESULT(no) ++]) + -+slock_t *apc_slock_create(slock_t *lock) -+{ -+ S_INIT_LOCK(lock); -+} ++AC_MSG_CHECKING(whether we should use mmap) ++AC_ARG_ENABLE(apc-mmap, ++[ --disable-apc-mmap ++ Disable mmap support and use IPC shm instead], ++[ ++ PHP_APC_MMAP=$enableval ++ AC_MSG_RESULT($enableval) ++], [ ++ PHP_APC_MMAP=yes ++ AC_MSG_RESULT(yes) ++]) + -+void apc_slock_destroy(slock_t *lock) -+{ -+ S_LOCK_FREE(lock); -+} ++AC_MSG_CHECKING(whether we should use semaphore locking instead of fcntl) ++AC_ARG_ENABLE(apc-sem, ++[ --enable-apc-sem ++ Enable semaphore locks instead of fcntl], ++[ ++ PHP_APC_SEM=$enableval ++ AC_MSG_RESULT($enableval) ++], [ ++ PHP_APC_SEM=no ++ AC_MSG_RESULT(no) ++]) ++ ++AC_MSG_CHECKING(whether we should use pthread mutex locking) ++AC_ARG_ENABLE(apc-pthreadmutex, ++[ --disable-apc-pthreadmutex ++ Disable pthread mutex locking ], ++[ ++ PHP_APC_PTHREADMUTEX=$enableval ++ AC_MSG_RESULT($enableval) ++], ++[ ++ PHP_APC_PTHREADMUTEX=yes ++ AC_MSG_RESULT(yes) ++]) ++ ++if test "$PHP_APC_PTHREADMUTEX" != "no"; then ++ orig_LIBS="$LIBS" ++ LIBS="$LIBS -lpthread" ++ AC_TRY_RUN( ++ [ ++ #include ++ #include ++ main() { ++ pthread_mutex_t mutex; ++ pthread_mutexattr_t attr; + -+void apc_slock_lock(slock_t *lock) -+{ -+ S_LOCK(lock); -+} ++ if(pthread_mutexattr_init(&attr)) { ++ puts("Unable to initialize pthread attributes (pthread_mutexattr_init)."); ++ return -1; ++ } ++ if(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { ++ puts("Unable to set PTHREAD_PROCESS_SHARED (pthread_mutexattr_setpshared), your system may not support shared mutex's."); ++ return -1; ++ } ++ if(pthread_mutex_init(&mutex, &attr)) { ++ puts("Unable to initialize the mutex (pthread_mutex_init)."); ++ return -1; ++ } ++ if(pthread_mutexattr_destroy(&attr)) { ++ puts("Unable to destroy mutex attributes (pthread_mutexattr_destroy)."); ++ return -1; ++ } ++ if(pthread_mutex_destroy(&mutex)) { ++ puts("Unable to destroy mutex (pthread_mutex_destroy)."); ++ return -1; ++ } + -+void apc_slock_unlock(slock_t *lock) -+{ -+ S_UNLOCK(lock); -+} ++ puts("pthread mutexs are supported!"); ++ return 0; ++ } ++ ], ++ [ dnl -Success- ++ PHP_ADD_LIBRARY(pthread) ++ ], ++ [ dnl -Failure- ++ AC_MSG_WARN([It doesn't appear that pthread mutexes are supported on your system]) ++ PHP_APC_PTHREADMUTEX=no ++ ], ++ [ ++ PHP_ADD_LIBRARY(pthread) ++ ] ++ ) ++ LIBS="$orig_LIBS" ++fi + -+zend_bool apc_slock_nonblocking_lock(slock_t *lock) -+{ -+ /* Technically we aren't supposed to call this directly, but the original -+ * code provides no method for absolute non-blocking locks, so we'll call into -+ * the TAS (test and set) functionality directly -+ */ -+ return !(TAS(lock)); /* if TAS returns 0 we obtained the lock, otherwise we failed */ -+} ++AC_MSG_CHECKING(whether we should use pthread read/write locking) ++AC_ARG_ENABLE(apc-pthreadrwlocks, ++[ --enable-apc-pthreadrwlocks ++ Enable pthread read/write locking ], ++[ ++ PHP_APC_PTHREADRWLOCK=$enableval ++ AC_MSG_RESULT($enableval) ++], ++[ ++ PHP_APC_PTHREADRWLOCK=no ++ AC_MSG_RESULT(no) ++]) + ++if test "$PHP_APC_PTHREADRWLOCK" != "no"; then ++ orig_LIBS="$LIBS" ++ LIBS="$LIBS -lpthread" ++ AC_TRY_RUN( ++ [ ++ #include ++ #include ++ main() { ++ pthread_rwlock_t rwlock; ++ pthread_rwlockattr_t attr; + -+#endif ++ if(pthread_rwlockattr_init(&attr)) { ++ puts("Unable to initialize pthread attributes (pthread_rwlockattr_init)."); ++ return -1; ++ } ++ if(pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { ++ puts("Unable to set PTHREAD_PROCESS_SHARED (pthread_rwlockattr_setpshared), your system may not support shared rwlock's."); ++ return -1; ++ } ++ if(pthread_rwlock_init(&rwlock, &attr)) { ++ puts("Unable to initialize the rwlock (pthread_rwlock_init)."); ++ return -1; ++ } ++ if(pthread_rwlockattr_destroy(&attr)) { ++ puts("Unable to destroy rwlock attributes (pthread_rwlockattr_destroy)."); ++ return -1; ++ } ++ if(pthread_rwlock_destroy(&rwlock)) { ++ puts("Unable to destroy rwlock (pthread_rwlock_destroy)."); ++ return -1; ++ } + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_spin.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_spin.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,48 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2007 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: Brian Shire | -+ +----------------------------------------------------------------------+ ++ puts("pthread rwlocks are supported!"); ++ return 0; ++ } ++ ], ++ [ dnl -Success- ++ PHP_ADD_LIBRARY(pthread) ++ APC_CFLAGS="-D_GNU_SOURCE" ++ ], ++ [ dnl -Failure- ++ AC_MSG_WARN([It doesn't appear that pthread rwlocks are supported on your system]) ++ PHP_APC_PTHREADRWLOCK=no ++ ], ++ [ ++ PHP_ADD_LIBRARY(pthread) ++ ] ++ ) ++ LIBS="$orig_LIBS" ++fi + -+ */ ++ AC_CACHE_CHECK([whether the target compiler supports builtin atomics], PHP_cv_APC_GCC_ATOMICS, [ ++ ++ AC_TRY_LINK([],[ ++ int foo = 0; ++ __sync_fetch_and_add(&foo, 1); ++ __sync_bool_compare_and_swap(&foo, 0, 1); ++ return __sync_fetch_and_add(&foo, 1); ++ ], ++ [PHP_cv_APC_GCC_ATOMICS=yes], ++ [PHP_cv_APC_GCC_ATOMICS=no]) ++ ]) ++ ++ if test "x${PHP_cv_APC_GCC_ATOMICS}" != "xno"; then ++ AC_DEFINE(HAVE_ATOMIC_OPERATIONS, 1, ++ [Define this if your target compiler supports builtin atomics]) ++ else ++ if test "$PHP_APC_PTHREADRWLOCK" != "no"; then ++ AC_MSG_WARN([Disabling pthread rwlocks, because of missing atomic operations]) ++ dnl - fall back would most likely be pthread mutexes ++ PHP_APC_PTHREADRWLOCK=no ++ fi ++ fi ++ ++AC_MSG_CHECKING(whether we should use spin locks) ++AC_ARG_ENABLE(apc-spinlocks, ++[ --enable-apc-spinlocks ++ Enable spin locks EXPERIMENTAL ], ++[ ++ PHP_APC_SPINLOCKS=$enableval ++ AC_MSG_RESULT($enableval) ++], ++[ ++ PHP_APC_SPINLOCKS=no ++ AC_MSG_RESULT(no) ++]) + -+/* $Id: apc_spin.h,v 3.1 2007/01/29 07:39:02 shire Exp $ */ + -+#ifndef APC_SPIN_H -+#define APC_SPIN_H ++AC_MSG_CHECKING(whether we should enable memory protection) ++AC_ARG_ENABLE(apc-memprotect, ++[ --enable-apc-memprotect ++ Enable mmap/shm memory protection], ++[ ++ PHP_APC_MEMPROTECT=$enableval ++ AC_MSG_RESULT($enableval) ++], [ ++ PHP_APC_MEMPROTECT=no ++ AC_MSG_RESULT(no) ++]) + -+#include "apc.h" ++if test "$PHP_APC" != "no"; then ++ test "$PHP_APC_MMAP" != "no" && AC_DEFINE(APC_MMAP, 1, [ ]) ++ test "$PHP_APC_FILEHITS" != "no" && AC_DEFINE(APC_FILEHITS, 1, [ ]) ++ ++ if test "$PHP_APC_DEBUG" != "no"; then ++ AC_DEFINE(__DEBUG_APC__, 1, [ ]) ++ fi ++ ++ if test "$PHP_APC_SEM" != "no"; then ++ AC_DEFINE(APC_SEM_LOCKS, 1, [ ]) ++ elif test "$PHP_APC_SPINLOCKS" != "no"; then ++ AC_DEFINE(APC_SPIN_LOCKS, 1, [ ]) ++ elif test "$PHP_APC_PTHREADRWLOCK" != "no"; then ++ AC_DEFINE(APC_PTHREADRW_LOCKS, 1, [ ]) ++ elif test "$PHP_APC_PTHREADMUTEX" != "no"; then ++ AC_DEFINE(APC_PTHREADMUTEX_LOCKS, 1, [ ]) ++ else ++ AC_DEFINE(APC_FCNTL_LOCKS, 1, [ ]) ++ fi ++ ++ if test "$PHP_APC_MEMPROTECT" != "no"; then ++ AC_DEFINE(APC_MEMPROTECT, 1, [ shm/mmap memory protection ]) ++ fi + -+#ifdef APC_SPIN_LOCKS ++ AC_CACHE_CHECK(for zend_set_lookup_function_hook, php_cv_zend_set_lookup_function_hook, ++ [ ++ orig_cflags=$CFLAGS ++ CFLAGS="$INCLUDES $EXTRA_INCLUDES" ++ AC_TRY_COMPILE([ ++#include "main/php.h" ++#include "Zend/zend_API.h" ++ ], [#ifndef zend_set_lookup_function_hook ++ (void) zend_set_lookup_function_hook; ++#endif], [ ++ php_cv_zend_set_lookup_function_hook=yes ++ ],[ ++ php_cv_zend_set_lookup_function_hook=no ++ ]) ++ CFLAGS=$orig_cflags ++ ]) ++ if test "$php_cv_zend_set_lookup_function_hook" = "yes"; then ++ AC_DEFINE(APC_HAVE_LOOKUP_HOOKS, 1, [ ]) ++ else ++ AC_DEFINE(APC_HAVE_LOOKUP_HOOKS, 0, [ ]) ++ fi + -+#include "pgsql_s_lock.h" ++ AC_CHECK_FUNCS(sigaction) ++ AC_CACHE_CHECK(for union semun, php_cv_semun, ++ [ ++ AC_TRY_COMPILE([ ++#include ++#include ++#include ++ ], [union semun x; x.val=1], [ ++ php_cv_semun=yes ++ ],[ ++ php_cv_semun=no ++ ]) ++ ]) ++ if test "$php_cv_semun" = "yes"; then ++ AC_DEFINE(HAVE_SEMUN, 1, [ ]) ++ else ++ AC_DEFINE(HAVE_SEMUN, 0, [ ]) ++ fi + -+pthread_mutex_t *apc_spin_create(); -+void apc_spin_destroy(pthread_mutex_t *lock); -+void apc_spin_lock(pthread_mutex_t *lock); -+void apc_spin_unlock(pthread_mutex_t *lock); -+zend_bool apc_spin_nonblocking_lock(pthread_mutex_t *lock); ++ AC_MSG_CHECKING(whether we should enable valgrind support) ++ AC_ARG_ENABLE(valgrind-checks, ++ [ --disable-valgrind-checks ++ Disable valgrind based memory checks], ++ [ ++ PHP_APC_VALGRIND=$enableval ++ AC_MSG_RESULT($enableval) ++ ], [ ++ PHP_APC_VALGRIND=yes ++ AC_MSG_RESULT(yes) ++ AC_CHECK_HEADER(valgrind/memcheck.h, ++ [AC_DEFINE([HAVE_VALGRIND_MEMCHECK_H],1, [enable valgrind memchecks])]) ++ ]) + -+#endif ++ apc_sources="apc.c php_apc.c \ ++ apc_cache.c \ ++ apc_compile.c \ ++ apc_debug.c \ ++ apc_fcntl.c \ ++ apc_main.c \ ++ apc_mmap.c \ ++ apc_sem.c \ ++ apc_shm.c \ ++ apc_pthreadmutex.c \ ++ apc_pthreadrwlock.c \ ++ apc_spin.c \ ++ pgsql_s_lock.c \ ++ apc_sma.c \ ++ apc_stack.c \ ++ apc_zend.c \ ++ apc_rfc1867.c \ ++ apc_signal.c \ ++ apc_pool.c \ ++ apc_iterator.c \ ++ apc_bin.c \ ++ apc_string.c " + -+#endif ++ PHP_CHECK_LIBRARY(rt, shm_open, [PHP_ADD_LIBRARY(rt,,APC_SHARED_LIBADD)]) ++ PHP_NEW_EXTENSION(apc, $apc_sources, $ext_shared,, \\$(APC_CFLAGS)) ++ PHP_SUBST(APC_SHARED_LIBADD) ++ PHP_SUBST(APC_CFLAGS) ++ PHP_INSTALL_HEADERS(ext/apc, [apc_serializer.h]) ++ AC_DEFINE(HAVE_APC, 1, [ ]) ++fi + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_stack.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_stack.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,105 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ +----------------------------------------------------------------------+ ++PHP_ARG_ENABLE(coverage, whether to include code coverage symbols, ++[ --enable-coverage DEVELOPERS ONLY!!], no, no) + -+ 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. ++if test "$PHP_COVERAGE" = "yes"; then + -+ All other licensing and usage conditions are those of the PHP Group. ++ if test "$GCC" != "yes"; then ++ AC_MSG_ERROR([GCC is required for --enable-coverage]) ++ fi ++ ++ dnl Check if ccache is being used ++ case `$php_shtool path $CC` in ++ *ccache*[)] gcc_ccache=yes;; ++ *[)] gcc_ccache=no;; ++ esac ++ ++ if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then ++ AC_MSG_ERROR([ccache must be disabled when --enable-coverage option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) ++ fi ++ ++ lcov_version_list="1.5 1.6 1.7 1.9" ++ ++ AC_CHECK_PROG(LCOV, lcov, lcov) ++ AC_CHECK_PROG(GENHTML, genhtml, genhtml) ++ PHP_SUBST(LCOV) ++ PHP_SUBST(GENHTML) ++ ++ if test "$LCOV"; then ++ AC_CACHE_CHECK([for lcov version], php_cv_lcov_version, [ ++ php_cv_lcov_version=invalid ++ lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` #' ++ for lcov_check_version in $lcov_version_list; do ++ if test "$lcov_version" = "$lcov_check_version"; then ++ php_cv_lcov_version="$lcov_check_version (ok)" ++ fi ++ done ++ ]) ++ else ++ lcov_msg="To enable code coverage reporting you must have one of the following LCOV versions installed: $lcov_version_list" ++ AC_MSG_ERROR([$lcov_msg]) ++ fi + -+ */ ++ case $php_cv_lcov_version in ++ ""|invalid[)] ++ lcov_msg="You must have one of the following versions of LCOV: $lcov_version_list (found: $lcov_version)." ++ AC_MSG_ERROR([$lcov_msg]) ++ LCOV="exit 0;" ++ ;; ++ esac + -+/* $Id: apc_stack.c,v 3.4 2006/03/12 00:31:45 rasmus Exp $ */ ++ if test -z "$GENHTML"; then ++ AC_MSG_ERROR([Could not find genhtml from the LCOV package]) ++ fi + -+#include "apc_stack.h" -+#include "apc.h" ++ PHP_ADD_MAKEFILE_FRAGMENT + -+struct apc_stack_t { -+ void** data; -+ int capacity; -+ int size; -+}; ++ dnl Remove all optimization flags from CFLAGS ++ changequote({,}) ++ CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'` ++ CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'` ++ changequote([,]) + -+apc_stack_t* apc_stack_create(int size_hint) ++ dnl Add the special gcc flags ++ CFLAGS="$CFLAGS -O0 -ggdb -fprofile-arcs -ftest-coverage" ++ CXXFLAGS="$CXXFLAGS -ggdb -O0 -fprofile-arcs -ftest-coverage" ++fi ++dnl vim: set ts=2 +diff -Naur a/ext/apc/config.w32 b/ext/apc/config.w32 +--- a/ext/apc/config.w32 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/config.w32 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,60 @@ ++// $Id: config.w32 309203 2011-03-14 06:47:16Z pajoye $ ++// vim:ft=javascript ++ ++ARG_ENABLE('apc', 'Whether to enable APC support', 'no'); ++ARG_ENABLE('apc-debug', 'Whether to enable APC debugging', 'no'); ++ARG_ENABLE('apc-filehits', 'Whether to enable cache request file info', 'no'); ++ARG_ENABLE('apc-spinlocks', 'Whether to use spin locks (experimental)', 'no'); ++ARG_ENABLE('apc-memprotect', 'Whether to enable memory protection (experimental)', 'no'); ++ARG_ENABLE('apc-srwlock-native', 'Whether to use SRWLOCK locks native (win7/2008 only)', 'no'); ++ARG_ENABLE('apc-srwlock-kernel', 'Whether to use SRWLOCK locks (loaded at runtime)', 'no'); ++ ++if(PHP_APC != 'no') +{ -+ apc_stack_t* stack = (apc_stack_t*) apc_emalloc(sizeof(apc_stack_t)); ++ var apc_sources = 'apc.c php_apc.c apc_cache.c apc_compile.c apc_debug.c ' + ++ 'apc_fcntl_win32.c apc_iterator.c apc_main.c apc_shm.c ' + ++ 'apc_sma.c apc_stack.c apc_rfc1867.c apc_zend.c apc_pool.c ' + ++ 'apc_bin.c apc_string.c'; + -+ stack->capacity = (size_hint > 0) ? size_hint : 10; -+ stack->size = 0; -+ stack->data = (void**) apc_emalloc(sizeof(void*) * stack->capacity); ++ if(PHP_APC_DEBUG != 'no') ++ { ++ ADD_FLAG('CFLAGS_APC', '/D __DEBUG_APC__=1'); ++ } + -+ return stack; -+} ++ if(PHP_APC_FILEHITS != 'no') ++ { ++ AC_DEFINE('APC_FILEHITS', 1); ++ } + -+void apc_stack_destroy(apc_stack_t* stack) -+{ -+ if (stack != NULL) { -+ apc_efree(stack->data); -+ apc_efree(stack); -+ } -+} ++ if(PHP_APC_MEMPROTECT != 'no') ++ { ++ AC_DEFINE('APC_MEMPROTECT', 1); ++ } + -+void apc_stack_clear(apc_stack_t* stack) -+{ -+ assert(stack != NULL); -+ stack->size = 0; -+} ++ if(PHP_APC_SRWLOCK_NATIVE != 'no') { ++ AC_DEFINE('APC_SRWLOCK_NATIVE', 1); ++ } else { ++ if(PHP_APC_SRWLOCK_KERNEL != 'no') { ++ AC_DEFINE('APC_SRWLOCK_KERNEL', 1); ++ ADD_FLAG('CFLAGS_APC', '/D WIN32_ONLY_COMPILER=1'); ++ ++ apc_sources += ' apc_windows_srwlock_kernel.c'; ++ } else { ++ if(PHP_APC_SPINLOCKS != 'no') { ++ AC_DEFINE('APC_SPIN_LOCKS', 1); ++ ADD_FLAG('CFLAGS_APC', '/D WIN32_ONLY_COMPILER=1'); ++ ++ apc_sources += ' apc_spin.c pgsql_s_lock.c'; ++ } else { ++ AC_DEFINE('APC_FCNTL_LOCKS', 1); ++ } ++ } ++ } + -+void apc_stack_push(apc_stack_t* stack, void* item) -+{ -+ assert(stack != NULL); -+ if (stack->size == stack->capacity) { -+ stack->capacity *= 2; -+ stack->data = apc_erealloc(stack->data, sizeof(void*)*stack->capacity); -+ } -+ stack->data[stack->size++] = item; -+} ++ AC_DEFINE('HAVE_APC', 1); ++ AC_DEFINE('HAVE_ATOMIC_OPERATIONS', 1); + -+void* apc_stack_pop(apc_stack_t* stack) -+{ -+ assert(stack != NULL && stack->size > 0); -+ return stack->data[--stack->size]; -+} ++ PHP_INSTALL_HEADERS("ext/apc", "apc_serializer.h"); + -+void* apc_stack_top(apc_stack_t* stack) -+{ -+ assert(stack != NULL && stack->size > 0); -+ return stack->data[stack->size-1]; ++ EXTENSION('apc', apc_sources); +} +diff -Naur a/ext/apc/INSTALL b/ext/apc/INSTALL +--- a/ext/apc/INSTALL 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/INSTALL 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,407 @@ ++Installation Instructions for APC ++--------------------------------- + -+void* apc_stack_get(apc_stack_t* stack, int n) -+{ -+ assert(stack != NULL && stack->size > n); -+ return stack->data[n]; -+} ++This version of APC should work on PHP 4.3.0 - 4.4.x and ++5.1.0 - 5.2.x. Yes, that means PHP 5.0.x is no longer ++supported. Upgrade to PHP 5.1.x or 5.2.x and you will ++notice all sorts of performance increases. + -+int apc_stack_size(apc_stack_t* stack) -+{ -+ assert(stack != NULL); -+ return stack->size; -+} ++CVS Instructions ++---------------- ++Building from CVS can be done like this: + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_stack.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_stack.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,58 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | George Schlossnagle | -+ +----------------------------------------------------------------------+ ++ svn co http://svn.php.net/repository/pecl/apc/trunk apc ++ cd apc ++ phpize ++ ./configure --with-php-config=/usr/local/php/bin/php-config ++ make ++ export TEST_PHP_ARGS='-n' ++ make test ++ make install + -+ 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. ++Suggested Configuration (in your php.ini file) ++---------------------------------------------- ++ extension=apc.so ++ apc.enabled=1 ++ apc.shm_size=128M ++ apc.ttl=7200 ++ apc.user_ttl=7200 ++ apc.enable_cli=1 + -+ All other licensing and usage conditions are those of the PHP Group. ++These are fully described at the bottom of this file. + -+ */ +++---------------------+ ++| QUICK INSTALL (DSO) | +++---------------------+ + -+/* $Id: apc_stack.h,v 3.4 2006/03/12 00:31:45 rasmus Exp $ */ ++These instructions assume your PHP installation is located in /usr/local/php and you ++want Apache optimizations (--with-apxs). + -+#ifndef APC_STACK_H -+#define APC_STACK_H ++$ gunzip -c apc_x.y.tar.gz | tar xf - ++$ cd apc_x.y ++$ /usr/local/php/bin/phpize ++$ ./configure --with-php-config=/usr/local/php/bin/php-config ++$ make ++$ make install + -+/* Basic stack datatype */ ++You will probably need to run the final command (make install) as root. + -+#define T apc_stack_t* -+typedef struct apc_stack_t apc_stack_t; /* opaque stack type */ ++The above sequence of commands will install a .so file in your PHP ++installation extension directory. The output of make install should display ++that path to the screen. + -+extern T apc_stack_create(int size_hint); -+extern void apc_stack_destroy(T stack); -+extern void apc_stack_clear(T stack); -+extern void apc_stack_push(T stack, void* item); -+extern void* apc_stack_pop(T stack); -+extern void* apc_stack_top(T stack); -+extern void* apc_stack_get(T stack, int n); -+extern int apc_stack_size(T stack); ++Next you must edit your php.ini file, which is normally located in ++/usr/local/php/lib/php.ini, and add the following line: + -+#undef T -+#endif ++ extension="apc.so" + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_zend.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_zend.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,277 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ +----------------------------------------------------------------------+ ++Replace "/path/to/php/extensions" with whatever path was displayed when you ++ran make install above. + -+ 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. ++Then restart your web server and consult the output of phpinfo(). If there is ++an informational section for APC, the installation was successful. + -+ All other licensing and usage conditions are those of the PHP Group. +++------------------------+ ++| QUICK INSTALL (Static) | +++------------------------+ + -+ */ ++APC will not successfully compile on all systems as a DSO. If you run into ++problems using the DSO quick install, you can try to compile it statically ++into PHP. (The DSO install is recommended, though.) + -+/* $Id: apc_zend.c,v 3.14 2007/04/02 22:57:10 rasmus Exp $ */ ++These instructions assume the current directory is the root of the PHP source ++tree, and that you have already configured PHP by running its bundled ++configure script. + -+#include "apc_zend.h" -+#include "apc_globals.h" ++$ cd ext ++$ gunzip -c apc_x.y.tar.gz | tar xf - ++$ cd .. ++$ ./buildconf ++$ ./config.nice ++$ make ++$ make install + -+void* apc_php_malloc(size_t n) -+{ -+ return emalloc(n); -+} ++Once this is complete, simply restart your web server. You do not need to ++modify your php.ini file to enable APC. + -+void apc_php_free(void* p) -+{ -+ efree(p); -+} +++-----------------+ ++| VERBOSE INSTALL | +++-----------------+ + -+#ifndef ZEND_VM_KIND_CALL /* Not currently defined by any ZE version */ -+# define ZEND_VM_KIND_CALL 1 -+#endif ++These instructions assume your PHP installation is located in /usr/local/php. + -+#ifndef ZEND_VM_KIND /* Indicates PHP < 5.1 */ -+# define ZEND_VM_KIND ZEND_VM_KIND_CALL -+#endif ++1. Unpack your distribution file. + -+#if defined(ZEND_ENGINE_2) && (ZEND_VM_KIND == ZEND_VM_KIND_CALL) -+# define APC_OPCODE_OVERRIDE -+#endif ++ You will have downloaded a file named something like apc_x.y.tar.gz. ++ Unzip this file with a command like ++ ++ gunzip apc_x.y.tar.gz ++ ++ Next you have to untar it with ++ ++ tar xvf apc_x.y.tar + -+#ifdef APC_OPCODE_OVERRIDE ++ This will create an apc_x.y directory. cd into this new directory: + -+#ifdef ZEND_ENGINE_2_1 -+/* Taken from Zend/zend_vm_execute.h */ -+#define _CONST_CODE 0 -+#define _TMP_CODE 1 -+#define _VAR_CODE 2 -+#define _UNUSED_CODE 3 -+#define _CV_CODE 4 -+static inline int _apc_opcode_handler_decode(zend_op *opline) -+{ -+ static const int apc_vm_decode[] = { -+ _UNUSED_CODE, /* 0 */ -+ _CONST_CODE, /* 1 = IS_CONST */ -+ _TMP_CODE, /* 2 = IS_TMP_VAR */ -+ _UNUSED_CODE, /* 3 */ -+ _VAR_CODE, /* 4 = IS_VAR */ -+ _UNUSED_CODE, /* 5 */ -+ _UNUSED_CODE, /* 6 */ -+ _UNUSED_CODE, /* 7 */ -+ _UNUSED_CODE, /* 8 = IS_UNUSED */ -+ _UNUSED_CODE, /* 9 */ -+ _UNUSED_CODE, /* 10 */ -+ _UNUSED_CODE, /* 11 */ -+ _UNUSED_CODE, /* 12 */ -+ _UNUSED_CODE, /* 13 */ -+ _UNUSED_CODE, /* 14 */ -+ _UNUSED_CODE, /* 15 */ -+ _CV_CODE /* 16 = IS_CV */ -+ }; -+ return (opline->opcode * 25) + (apc_vm_decode[opline->op1.op_type] * 5) + apc_vm_decode[opline->op2.op_type]; -+} ++ cd apc_x.y + -+# define APC_ZEND_OPLINE zend_op *opline = execute_data->opline; -+# define APC_OPCODE_HANDLER_DECODE(opline) _apc_opcode_handler_decode(opline) -+# if PHP_MAJOR_VERSION >= 6 -+# define APC_OPCODE_HANDLER_COUNT ((25 * 152) + 1) -+# else -+# define APC_OPCODE_HANDLER_COUNT ((25 * 151) + 1) -+# endif -+# define APC_REPLACE_OPCODE(opname) { int i; for(i = 0; i < 25; i++) if (zend_opcode_handlers[(opname*25) + i]) zend_opcode_handlers[(opname*25) + i] = apc_op_##opname; } ++2. Run phpize. + -+#else /* ZE2.0 */ -+# define APC_ZEND_ONLINE -+# define APC_OPCODE_HANDLER_DECODE(opline) (opline->opcode) -+# define APC_OPCODE_HANDLER_COUNT 512 -+# define APC_REPLACE_OPCODE(opname) zend_opcode_handlers[opname] = apc_op_##opname; -+#endif ++ phpize is a script that should have been installed with PHP, and is ++ normally located in /usr/local/php/bin assuming you installed PHP in ++ /usr/local/php. (If you do not have the phpize script, you must reinstall ++ PHP and be sure not to disable PEAR.) + -+static opcode_handler_t *apc_original_opcode_handlers; -+static opcode_handler_t apc_opcode_handlers[APC_OPCODE_HANDLER_COUNT]; ++ Run the phpize command: ++ ++ /usr/local/php/bin/phpize + -+#define APC_EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset)) ++ Its output should resemble this: + -+static zval *apc_get_zval_ptr(znode *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC) -+{ -+ *freeval = NULL; ++ autoheader: `config.h.in' is created ++ You should update your `aclocal.m4' by running aclocal. ++ Configuring for: ++ PHP Api Version: 20020918 ++ Zend Module Api No: 20020429 ++ Zend Extension Api No: 20021010 ++ ++ phpize should create a configure script in the current directory. If you ++ get errors instead, you might be missing some required development tools, ++ such as autoconf or libtool. You can try downloading the latest versions ++ of those tools and running phpize again. ++ ++3. Run the configure script. ++ ++ phpize creates a configure script. The only option you need to specify is ++ the location of your php-config script: + -+ switch (node->op_type) { -+ case IS_CONST: -+ return &(node->u.constant); -+ case IS_VAR: -+ return APC_EX_T(node->u.var).var.ptr; -+ case IS_TMP_VAR: -+ return (*freeval = &APC_EX_T(node->u.var).tmp_var); -+#ifdef ZEND_ENGINE_2_1 -+ case IS_CV: -+ { -+ zval ***ret = &execute_data->CVs[node->u.var]; ++ ./configure --enable-apc + -+ if (!*ret) { -+ zend_compiled_variable *cv = &EG(active_op_array)->vars[node->u.var]; ++ php-config should be located in the same directory as phpize. + -+ if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void**)ret)==FAILURE) { -+ apc_nprint("Undefined variable: %s", cv->name); -+ return &EG(uninitialized_zval); -+ } -+ } -+ return **ret; -+ } -+#endif -+ case IS_UNUSED: -+ default: -+ return NULL; -+ } -+} ++ If you prefer to use mmap instead of the default IPC shared memory support, ++ add --enable-apc-mmap to your configure line. + -+static int apc_op_ZEND_INCLUDE_OR_EVAL(ZEND_OPCODE_HANDLER_ARGS) -+{ -+ APC_ZEND_OPLINE -+ zval *freeop1 = NULL; -+ zval *inc_filename = NULL, tmp_inc_filename; -+ char realpath[MAXPATHLEN]; -+ php_stream_wrapper *wrapper; -+ char *path_for_open; -+ int ret = 0; -+ #ifdef ZEND_ENGINE_2 -+ apc_opflags_t* flags = NULL; -+ #endif ++ If you prefer to use sysv IPC semaphores over the safer fcntl() locks, add ++ --enable-sem to your configure line. If you don't have a problem ++ with your server segaulting, or any other unnatural accumulation of ++ semaphores on your system, the semaphore based locking is slightly faster. ++ ++4. Compile and install the files. Simply type: make install + -+ if (Z_LVAL(opline->op2.u.constant) != ZEND_INCLUDE_ONCE && -+ Z_LVAL(opline->op2.u.constant) != ZEND_REQUIRE_ONCE) { -+ return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -+ } ++ (You may need to be root in order to install) + -+ inc_filename = apc_get_zval_ptr(&opline->op1, &freeop1, execute_data TSRMLS_CC); -+ if (Z_TYPE_P(inc_filename) != IS_STRING) { -+ tmp_inc_filename = *inc_filename; -+ zval_copy_ctor(&tmp_inc_filename); -+ convert_to_string(&tmp_inc_filename); -+ inc_filename = &tmp_inc_filename; -+ } ++ If you encounter errors from libtool or gcc during this step, please ++ contact the project maintainer (dcowgill@php.net). + -+ wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(inc_filename), &path_for_open, 0 TSRMLS_CC); -+ if (wrapper != &php_plain_files_wrapper || -+ !IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) || -+ !expand_filepath(path_for_open, realpath TSRMLS_CC)) { -+ /* Fallback to original handler */ -+ if (inc_filename == &tmp_inc_filename) { -+ zval_dtor(&tmp_inc_filename); -+ } -+ return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -+ } ++5. Edit your php.ini + -+ if (zend_hash_exists(&EG(included_files), realpath, strlen(realpath) + 1)) { -+ if (!(opline->result.u.EA.type & EXT_TYPE_UNUSED)) { -+ ALLOC_INIT_ZVAL(APC_EX_T(opline->result.u.var).var.ptr); -+ ZVAL_TRUE(APC_EX_T(opline->result.u.var).var.ptr); -+ } -+ if (inc_filename == &tmp_inc_filename) { -+ zval_dtor(&tmp_inc_filename); -+ } -+ if (freeop1) { -+ zval_dtor(freeop1); -+ } -+ execute_data->opline++; -+ return 0; -+ } ++ make install should have printed a line resembling the following: + -+ if (inc_filename == &tmp_inc_filename) { -+ zval_dtor(&tmp_inc_filename); -+ } ++ Installing shared extensions: /path/to/extension/ + -+ if(APCG(reserved_offset) != -1) { -+ /* Insanity alert: look into apc_compile.c for why a void** is cast to a apc_opflags_t* */ -+ flags = (apc_opflags_t*) & (execute_data->op_array->reserved[APCG(reserved_offset)]); -+ } ++ Copy the path /path/to/extension/ and add the following line to your ++ php.ini file (normally located in /usr/local/php/lib/php.ini): + -+#ifdef ZEND_ENGINE_2 -+ if(flags && flags->deep_copy == 1) { -+ /* Since the op array is a local copy, we can cheat our way through the file inclusion by temporarily -+ * changing the op to a plain require/include, calling its handler and finally restoring the opcode. -+ */ -+ Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE_ONCE) ? ZEND_INCLUDE : ZEND_REQUIRE; -+ ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -+ Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE) ? ZEND_INCLUDE_ONCE : ZEND_REQUIRE_ONCE; -+#else -+ if(0) { -+ /* do nothing, have nothing, be nothing */ -+#endif -+ } else { -+ ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -+ } ++ extension="apc.so" + -+ return ret; -+} ++ If you don't have a php.ini file in that location, you can create it now. + -+void apc_zend_init(TSRMLS_D) -+{ -+ zend_extension dummy_ext; -+#ifdef ZEND_ENGINE_2 -+ APCG(reserved_offset) = zend_get_resource_handle(&dummy_ext); -+ assert(APCG(reserved_offset) == dummy_ext.resource_number); -+ assert(APCG(reserved_offset) != -1); -+ assert(sizeof(apc_opflags_t) <= sizeof(void*)); -+#endif -+ if (!APCG(include_once)) { -+ /* If we're not overriding the INCLUDE_OR_EVAL handler, then just skip this malarkey */ -+ return; -+ } ++6. Restart the web server and test the installation. + -+ memcpy(apc_opcode_handlers, zend_opcode_handlers, sizeof(apc_opcode_handlers)); ++ Restart your web server now (for apache, it's apachectl restart) and ++ create a small test PHP file in your document root. The file should ++ contain just the following line: + -+ /* 5.0 exposes zend_opcode_handlers differently than 5.1 and later */ -+#ifdef ZEND_ENGINE_2_1 -+ apc_original_opcode_handlers = zend_opcode_handlers; -+ zend_opcode_handlers = apc_opcode_handlers; -+#else -+ apc_original_opcode_handlers = apc_opcode_handlers; -+#endif ++ + -+ APC_REPLACE_OPCODE(ZEND_INCLUDE_OR_EVAL); -+} ++ Request that file in a web browser. If there is an entry for APC in the ++ list of installed modules, the installation was successful. + -+void apc_zend_shutdown(TSRMLS_D) -+{ -+ if (!APCG(include_once)) { -+ /* Nothing changed, nothing to restore */ -+ return; -+ } ++ If APC is not listed, consult your web server error log. If it contains an ++ error message saying that it can't load the APC extension, your system ++ might not be able to load shared libraries created with PHP's build ++ system. One alternative would be to compile APC statically into PHP. See ++ the Quick Install (Static) instructions above. + -+#ifdef ZEND_ENGINE_2_1 -+ zend_opcode_handlers = apc_original_opcode_handlers; -+#else -+ memcpy(zend_opcode_handlers, apc_original_opcode_handlers, sizeof(apc_opcode_handlers)); -+#endif -+} ++ You should consult your error log anyway to see if APC generated any ++ errors. On BSD-based platforms, it is typical for APC to be unable to ++ allocate the default-sized shared memory segment. See below for hints on ++ raising your system's shared memory limitations. + -+#else /* Opcode Overrides unavailable */ +++-----------------+ ++| CONFIGURING APC | +++-----------------+ + -+void apc_zend_init(TSRMLS_D) { } -+void apc_zend_shutdown(TSRMLS_D) { } ++Although the default APC settings are fine for many installations, serious ++users should consider tuning the following parameters: + -+#endif /* APC_OPCODE_OVERRIDE */ ++ OPTION DESCRIPTION ++ ------------------ -------------------------------------------------- ++ apc.enabled This can be set to 0 to disable APC. This is ++ primarily useful when APC is statically compiled ++ into PHP, since there is no other way to disable ++ it (when compiled as a DSO, the zend_extension ++ line can just be commented-out). ++ (Default: 1) ++ ++ apc.shm_segments The number of shared memory segments to allocate ++ for the compiler cache. If APC is running out of ++ shared memory but you have already set ++ apc.shm_size as high as your system allows, you ++ can try raising this value. Setting this to a ++ value other than 1 has no effect in mmap mode ++ since mmap'ed shm segments don't have size limits. ++ (Default: 1) ++ ++ apc.shm_size The size of each shared memory segment in MB. ++ By default, some systems (including most BSD ++ variants) have very low limits on the size of a ++ shared memory segment. M/G suffixes must be used. ++ (Default: 30) + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/apc_zend.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/apc_zend.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,53 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ +----------------------------------------------------------------------+ ++ ++ apc.optimization This option has been deprecated. ++ (Default: 0) ++ ++ apc.num_files_hint A "hint" about the number of distinct source files ++ that will be included or requested on your web ++ server. Set to zero or omit if you're not sure; ++ this setting is mainly useful for sites that have ++ many thousands of source files. ++ (Default: 1000) + -+ 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. ++ apc.user_entries_hint Just like num_files_hint, a "hint" about the number ++ of distinct user cache variables to store. ++ Set to zero or omit if you're not sure; ++ (Default: 4096) + -+ All other licensing and usage conditions are those of the PHP Group. ++ apc.ttl The number of seconds a cache entry is allowed to ++ idle in a slot in case this cache entry slot is ++ needed by another entry. Leaving this at zero ++ means that your cache could potentially fill up ++ with stale entries while newer entries won't be ++ cached. ++ (Default: 0) + -+ */ ++ apc.user_ttl The number of seconds a user cache entry is allowed ++ to idle in a slot in case this cache entry slot is ++ needed by another entry. Leaving this at zero ++ means that your cache could potentially fill up ++ with stale entries while newer entries won't be ++ cached. ++ (Default: 0) + -+/* $Id: apc_zend.h,v 3.8 2006/09/01 21:59:16 pollita Exp $ */ + -+#ifndef APC_ZEND_H -+#define APC_ZEND_H ++ apc.gc_ttl The number of seconds that a cache entry may ++ remain on the garbage-collection list. This value ++ provides a failsafe in the event that a server ++ process dies while executing a cached source file; ++ if that source file is modified, the memory ++ allocated for the old version will not be ++ reclaimed until this TTL reached. Set to zero to ++ disable this feature. ++ (Default: 3600) + -+/* Utilities for interfacing with the zend engine */ ++ apc.cache_by_default On by default, but can be set to off and used in ++ conjunction with positive apc.filters so that files ++ are only cached if matched by a positive filter. ++ (Default: On) + -+#include "apc.h" -+#include "apc_php.h" ++ apc.filters A comma-separated list of POSIX extended regular ++ expressions. If any pattern matches the source ++ filename, the file will not be cached. Note that ++ the filename used for matching is the one passed ++ to include/require, not the absolute path. If the ++ first character of the expression is a + then the ++ expression will be additive in the sense that any ++ files matched by the expression will be cached, and ++ if the first character is a - then anything matched ++ will not be cached. The - case is the default, so ++ it can be left off. ++ (Default: "") + -+extern void* apc_php_malloc(size_t n); -+extern void apc_php_free(void* p); ++ apc.mmap_file_mask If compiled with MMAP support by using --enable-mmap ++ this is the mktemp-style file_mask to pass to the ++ mmap module for determing whether your mmap'ed memory ++ region is going to be file-backed or shared memory ++ backed. For straight file-backed mmap, set it to ++ something like /tmp/apc.XXXXXX (exactly 6 X's). ++ To use POSIX-style shm_open/mmap put a ".shm" ++ somewhere in your mask. eg. "/apc.shm.XXXXXX" ++ You can also set it to "/dev/zero" to use your ++ kernel's /dev/zero interface to anonymous mmap'ed ++ memory. Leaving it undefined will force an ++ anonymous mmap. ++ (Default: "") + -+extern void apc_zend_init(TSRMLS_D); -+extern void apc_zend_shutdown(TSRMLS_D); ++ apc.slam_defense ** DEPRECATED - Use apc.write_lock instead ** ++ On very busy servers whenever you start the server or ++ modify files you can create a race of many processes ++ all trying to cache the same file at the same time. ++ This option sets the percentage of processes that will ++ skip trying to cache an uncached file. Or think of it ++ as the probability of a single process to skip caching. ++ For example, setting this to 75 would mean that there is ++ a 75% chance that the process will not cache an uncached ++ file. So the higher the setting the greater the defense ++ against cache slams. Setting this to 0 disables this ++ feature. ++ (Default: 0) + -+#endif ++ apc.file_update_protection ++ When you modify a file on a live web server you really ++ should do so in an atomic manner. That is, write to a ++ temporary file and rename (mv) the file into its permanent ++ position when it is ready. Many text editors, cp, tar and ++ other such programs don't do this. This means that there ++ is a chance that a file is accessed (and cached) while it ++ is still being written to. This file_update_protection ++ setting puts a delay on caching brand new files. The ++ default is 2 seconds which means that if the modification ++ timestamp (mtime) on a file shows that it is less than 2 ++ seconds old when it is accessed, it will not be cached. ++ The unfortunate person who accessed this half-written file ++ will still see weirdness, but at least it won't persist. ++ If you are certain you always atomically update your files ++ by using something like rsync which does this correctly, you ++ can turn this protection off by setting it to 0. If you ++ have a system that is flooded with io causing some update ++ procedure to take longer than 2 seconds, you may want to ++ increase this a bit. ++ (Default: 2) + -+/* -+ * Local variables: -+ * tab-width: 4 -+ * c-basic-offset: 4 -+ * End: -+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker -+ * vim<600: expandtab sw=4 ts=4 sts=4 -+ */ -Index: php-5.2.3/ext/apc/CHANGELOG -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/CHANGELOG 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,192 @@ -+3.0.14: 2007-03-21 -+- Build fix (Shire) -+- Don't hook the upload hook if APC is disabled (Rasmus) -+- Local shadow cache support (Gopal) -+- Avoid uneccessary loops over op_arrays for "known" auto-globals (Gopal) -+- Fix apc_add() to overwrite timed out user entries (Rasmus) -+- Fix double inclusion of files with conditional classes in php4 (Gopal) -+- Allocator fixes to reduce fragmentation (Gopal) ++ apc.enable_cli Mostly for testing and debugging. Setting this enables APC ++ for the CLI version of PHP. Normally you wouldn't want to ++ create, populate and tear down the APC cache on every CLI ++ request, but for various test scenarios it is handy to be ++ able to enable APC for the CLI version of APC easily. ++ (Default: 0) + -+3.0.13: 2007-02-24 -+- File upload progress (Rasmus) -+- Pthread mutex and spin locks (Shire) -+- Recursive zval support for apc_fetch/_store (Shire, Gopal) -+- apc.stat_ctime flag for ctime checks (Rasmus) -+- Multiple key fetches with apc_fetch (Shire) -+- Canary checks for shm memory deallocation (Gopal) -+- Add hooks for external optimizer (Shire) -+- Obsolete and remove apc optimizer (Gopal) -+- APC info changes - cache insert rate, hit and miss rates (Shire) -+- Fix apc_load_constants (Gopal) -+- Rewrite dump opcode code to use vld (Gopal) -+- Use apc_[ewn]print functions for error reporting (Shire) -+- Auto global fixes and refactoring (Gopal, Shire) -+- Fix memory leaks in object serialization (Ilia) -+- Memory cleanup code for destructor order (Gopal) -+- Win32 build fixes (Ilia, Wez) -+- ZTS and Php 4 build fixes (Bjori) -+- Add apc_add() function (Rasmus) -+- Add optional limited flag to apc_sma_info() (Rasmus) ++ apc.max_file_size Prevents large files from being cached. ++ (Default: 1M) + -+3.0.12p2: 2006-09-05 -+- Package version up ++ apc.stat Whether to stat the main script file and the fullpath ++ includes. If you turn this off you will need to restart ++ your server in order to update scripts. ++ (Default: 1) + -+3.0,12p1: 2006-09-05 -+- PHP4 build fixes ++ apc.canonicalize Whether to canonicalize paths in stat=0 mode or ++ fall back to stat behaviour if set to 0 ++ (Default: 0) + -+3.0.12: 2006-09-05 -+- PHP 5.2 compatibility (Gopal) -+- TSRM fixes (Gopal) -+- Add extra flags to op_array->reserved to improve op array -+ processing code (Gopal) -+- Fix crashes in optimizer and cli mode (Ilia) -+- Optimizer fixes for PHP5 (Ilia, Gopal) -+- Allow multiple inclusions of a file with a dynamic class (Gopal) -+- Php 4 function table and properties fixes (Gopal) -+- Fix memory leaks in apc_cache_info (Gopal) ++ apc.write_lock On busy servers when you first start up the server, or when ++ many files are modified, you can end up with all your processes ++ trying to compile and cache the same files. With write_lock ++ enabled, only one process at a time will try to compile an ++ uncached script while the other processes will run uncached ++ instead of sitting around waiting on a lock. ++ (Default: 1) + -+3.0.11: 2006-08-16 -+- Made --enable-apc-mmap the default compile option (for real this time) -+- Add an optional flag to apc_cache_info() and some apc.php tweaks to make it -+ only fetch header information to make it useful when you have tens of -+ thousands of entries. (Brian Shire) -+- 64-bit fixes (George) -+- Don't mix Full Path and Inode keys (George) -+- Override ZEND_INCLUDE_OR_EVAL opcode (when possible) to speed up use of -+ require_once() and include_once() statements. (Sara) -+- Add a non-blocking write_lock for cache inserts. This is a better approach -+ to prevent cache slams and deprecates the slam_defense setting. (Rasmus) -+- A bit of work on the optimizer. (Sara) -+- Various memory issues resolved. (Gopal) ++ apc.report_autofilter Logs any scripts that were automatically excluded from being ++ cached due to early/late binding issues. ++ (Default: 0) + -+3.0.10: 2006-03-11 -+- Add apc.stat ini flag which defaults to 1. If set to 0, the main script and any fullpath -+ includes will not be stat'ed for any changes. You will have to restart the server if you -+ change anything. This mode increases performance quite a bit, especially if you have a -+ lot of includes. ++ apc.rfc1867 RFC1867 File Upload Progress hook handler is only available ++ if you compiled APC against PHP 5.2.0 or later. When enabled ++ any file uploads which includes a field called ++ APC_UPLOAD_PROGRESS before the file field in an upload form ++ will cause APC to automatically create an upload_ ++ user cache entry where is the value of the ++ APC_UPLOAD_PROGRESS form entry. + -+- Get rid of the lock safety net hack I added in 3.0.9. It seems to cause more problems -+ than it solves. I'll need to revisit locking and signal handling at some point soon. ++ Note that the file upload tracking is not threadsafe at this ++ point, so new uploads that happen while a previous one is ++ still going will disable the tracking for the previous. ++ (Default: 0) + -+3.0.9: 2006-03-04 -+- Eliminate rand() call when slam_defense is not set (Rasmus) -+- Fix for __isset problem (Gopal) -+- Rewrite allocator from a "best fit" to a "next fit" algorithm (Rasmus) -+- Added a Cache Full counter so we have an idea how many times the segment has filled up causing an expunge (Rasmus) -+- Report back the correct number of available bytes in the segment instead of the allocated bytes. (Rasmus) -+- Add cache busy flag which is set when an expunge is underway (Rasmus) -+- Add automatic serialization of objects in apc_store() (Marcus) -+- 64-bit .ini flag fix (Rasmus) -+- Static members fix (Gopal) -+- sma_cleanup() mem leak fix (Rasmus) -+- Fix for http://pecl.php.net/bugs/5311 (Rasmus) -+- Fix autoglobals JIT bug (Gopal) -+- Fix instance bug (Gopal) -+- Add a lock cleanup safety net to request shutdown (Rasmus) -+- Fix apc.slam_defense edge-case bug (Rasmus) -+- User entry memory usage tracking support (Ilia) -+- Allow keys used in apc_store/apc_fetch/apc_delete to be binary safe and prevent conflicts between keys that are found at the start of other keys. (Ilia) ++ apc.rfc1867_prefix Key prefix to use for the user cache entry generated by ++ rfc1867 upload progress functionality. ++ (Default: "upload_") ++ ++ apc.rfc1867_name Specify the hidden form entry name that activates APC upload ++ progress and specifies the user cache key suffix. ++ (Default: "APC_UPLOAD_PROGRESS") ++ ++ apc.rfc1867_freq The frequency that updates should be made to the user cache ++ entry for upload progress. This can take the form of a ++ percentage of the total file size or a size in bytes ++ optionally suffixed with 'k', 'm', or 'g' for kilobytes, ++ megabytes, or gigabytes respectively (case insensitive). ++ A setting of 0 updates as often as possible, which may cause ++ slower uploads. ++ (Default: 0) + -+3.0.8: 2005-08-24 -+Fix invalid free in globals destructor introduced in 3.0.7 (Rasmus) -+Cache corruption fix in cache-full cleanup code (Gopal) ++ apc.localcache ** REMOVED ++ apc.localcache.size ** REMOVED ++ ++ apc.include_once_override ++ Optimize include_once and require_once calls and avoid the ++ expensive system calls used. ++ (Default: 0) + -+3.0.7: 2005-08-16 -+- Fix to apc.php to show final segment in frag chart. (Ilia) -+- A couple of win32 fixes. (Frank) -+- Add apc.enable_cli ini directive. (Rasmus) -+- Add test cases. (Marcus) -+- Fix apc_define_constants() bug - http://pecl.php.net/bugs/5084 (Rasmus) -+- Simplify user cache handling by removing the user_cache_stack (Rasmus) -+- Fix apc_fetch() memory corruption (Andrei,Rasmus) -+- Added apc.max_file_size INI setting that allows exclusion of large files from being cached. Default file size limit, 1 megabyte. (Ilia) ++ apc.serializer ++ Defines which serializer should be used. Default is the ++ standard PHP serializer. Other can be used without having ++ to re compile apc, like igbinary for example. ++ (apc.serializer=igbinary) +diff -Naur a/ext/apc/LICENSE b/ext/apc/LICENSE +--- a/ext/apc/LICENSE 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/LICENSE 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,68 @@ ++-------------------------------------------------------------------- ++ The PHP License, version 3.01 ++Copyright (c) 1999 - 2011 The PHP Group. All rights reserved. ++-------------------------------------------------------------------- + -+3.0.6: 2005-07-30 -+- Added apc.php to package.xml file. -+- Track per-entry memory usage. (Val) -+- Various apc.php fixes and enhancements. (Ralf, Ilia, Rasmus) -+- fcntl locking robustness fixes. (Rasmus) -+- Shared read-locks where possible. (Rasmus) -+- Added file_update_protection configuration parameter. (Rasmus) -+- Windows ZTS fixes (Frank) ++Redistribution and use in source and binary forms, with or without ++modification, is permitted provided that the following conditions ++are met: + -+3.0.5: 2005-07-27 -+- Make it easier for sapis that only populate file_handle->filename to use APC. (Rasmus) -+- Support extensions such as bcompiler that need to hook into compile_file. (Val) -+- Ralf Becker's apcgui code has now become the default apc.php status page. (Ralf, Rasmus, Ilia) -+- Segfault in cache cleanup code (Ilia, Rasmus) ++ 1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in ++ the documentation and/or other materials provided with the ++ distribution. ++ ++ 3. The name "PHP" must not be used to endorse or promote products ++ derived from this software without prior written permission. For ++ written permission, please contact group@php.net. ++ ++ 4. Products derived from this software may not be called "PHP", nor ++ may "PHP" appear in their name, without prior written permission ++ from group@php.net. You may indicate that your software works in ++ conjunction with PHP by saying "Foo for PHP" instead of calling ++ it "PHP Foo" or "phpfoo" ++ ++ 5. The PHP Group may publish revised and/or new versions of the ++ license from time to time. Each version will be given a ++ distinguishing version number. ++ Once covered code has been published under a particular version ++ of the license, you may always continue to use it under the terms ++ of that version. You may also choose to use such covered code ++ under the terms of any subsequent version of the license ++ published by the PHP Group. No one other than the PHP Group has ++ the right to modify the terms applicable to covered code created ++ under this License. + -+3.0.4: 2005-07-18 -+- Add win32 support (Edin ) -+- Add --with-apxs switch to work around problem when loading APC into Apache binary compiled with LFS switches (Rasmus) -+- A couple of other minor fixes ++ 6. Redistributions of any form whatsoever must retain the following ++ acknowledgment: ++ "This product includes PHP software, freely available from ++ ". + -+3.0.3: 2005-07-05 -+- Fix compile problem against PHP 5.0.x ++THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ++ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP ++DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++OF THE POSSIBILITY OF SUCH DAMAGE. + -+3.0.2: 2005-07-05 -+- Better shm error message ++-------------------------------------------------------------------- + -+3.0.1: 2005-07-05 -+- PHP4 build fix ++This software consists of voluntary contributions made by many ++individuals on behalf of the PHP Group. + -+3.0: 2005-06-23 -+- PHP 5.1 support (Arun, Gopal, Rasmus) -+- Major Inheritance bug fix (Arun, Gopal) ++The PHP Group can be contacted via Email at group@php.net. + -+2.0: 2003-02-10 -+- ground-up rewrite sharing none of the original source code (djc) ++For more information on the PHP Group and the PHP project, ++please see . + -+1.0.10: -+- merge mmap / shm code to be in one file, module supports both modes now [mpb 2001-05-15] -+- added apc.mode config parameter [mpb 2001-05-15] NOTE: You'll have to add -+ this parameter to your php.ini file to activate apc shm or mmap caching -+- generic source cleanup (missing includes, PATH_MAX usage etc) [mpb -+ 2001-05-15] -+- fixed: realpath return result checking in generate_key [mpb 2001-05-15] -+- updated: gui updated (extras/apc_gui-1.0.2.tar.gz) -+- experminental 'fast' cache-retrieval [djc 2001-05-20] -+- fixed regex support [gws 2001-05-16] -+- enhanced reader-writer lock support [rg 2001-05-07] ++PHP includes the Zend Engine, freely available at ++. +diff -Naur a/ext/apc/NOTICE b/ext/apc/NOTICE +--- a/ext/apc/NOTICE 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/NOTICE 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,43 @@ ++This is the NOTICE file that holds acknowledgements and stuff. + -+1.0.9: -+- fixed (?) memory alignment bug on 64 bit archiecures -+- added many cache visibiliy functions -+- added opional fcntl locks under shm version -+- numerous bug fixes ++The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. ++This extension is being released under the PHP License for complete compliance ++with PHP and to encourage wide-spread use. It is our intention that this ++project be kept open source and that all commercial spin-offs contribute their ++modifications back into the public source-tree. + -+1.0.8: -+- added ability to detect and decompile compiled files placed as 'source' -+ [gws,dw 2001-01-30] -+- fixed apc_rstat bug [gws 2001-01-29] -+- added hack to support included urls [gws 2001-01-30] -+- fixed apc_cache_index [mb 2001-01-31] -+- added multiple regex support [gs 2001-02-03] -+- added apc_cache_info [mb,gs 2001-02-03] ++Creators: ++ Daniel Cowgill ++ George Schlossnagle + -+1.0.7: -+- partially fixed for Solaris [gws 2001-01-29] -+- fixed mtime support for relative includes [gws 2001-01-29] -+- code cleanup [yg,ta,gws 2001-01-29] ++PHP5 support and major features by: ++ Arun C. Murthy ++ Gopal Vijayaraghavan ++ Rasmus Lerdorf ++ ++This software was contributed to PHP by Community Connect Inc. in 2002 ++and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. ++Future revisions and derivatives of this source code must acknowledge ++Community Connect Inc. as the original contributor of this module by ++leaving this note intact in the source code. ++ ++All other licensing and usage conditions are those of the PHP Group. + -+1.0.6: -+- support for mtime in mmap [yg,gws 2001-01-27] -+- fixed indexed-array initialization bug [djc,gws 2001-01-27] ++We would like to thank Community Connect Inc. and Yahoo! Inc. for supporting ++this project and providing a challenging and stimulating environment in ++which exciting projects can happen. + -+1.0.5: -+- support for relative include paths [djc,gws 2001-01-19] -+- class member array support fixed [djc 2001-01-18] -+- added apc_cache_index [gws 2001-01-18] ++Contributors: ++ Mike Bretz bug fixes, GUI, and lots of work ++ Ricardo Galli changed read-write locks to prefer readers ++ Yann Grossel bug fixes ++ Thies Arntzen bug fixes ++ Sara Golemon optimizer work + -+1.0.4: -+- support for class hierarchies greater than two levels deep [djc 2001-01-17] ++Special Thanks: ++ Florian Baumert help debugging phplib problems ++ Thomas Duffey help debugging inheritance issues ++ Vibol Hou help debugging phplib problems ++ Angel Li diffs for ANSI comment compliance ++ Christian Rishøj help debugging phplib problems ++ Sascha Schumann memory error bug fix +diff -Naur a/ext/apc/pgsql_s_lock.c b/ext/apc/pgsql_s_lock.c +--- a/ext/apc/pgsql_s_lock.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/pgsql_s_lock.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,391 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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. | ++ +----------------------------------------------------------------------+ ++ | The following code was ported from the PostgreSQL project, please | ++ | see appropriate copyright notices that follow. | ++ | Initial conversion by Brian Shire | ++ +----------------------------------------------------------------------+ + -+1.0.3: -+- fixed support for class inheritance [djc 2001-01-16] ++ */ + -+1.0.2: -+- support for inherited classes [gws 2001-01-15] -+- support for intialization of class variables and objects [gws 2001-01-13] ++/* $Id: pgsql_s_lock.c 307048 2011-01-03 23:53:17Z kalle $ */ + -+1.0.1: -+- added optional file modification time check [djc 2001-01-12] -Index: php-5.2.3/ext/apc/config.m4 -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/config.m4 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,214 @@ -+dnl -+dnl $Id: config.m4,v 3.25 2007/02/24 15:57:59 rasmus Exp $ -+dnl ++/*------------------------------------------------------------------------- ++ * ++ * s_lock.c ++ * Hardware-dependent implementation of spinlocks. ++ * ++ * ++ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group ++ * Portions Copyright (c) 1994, Regents of the University of California ++ * ++ * ++ * IDENTIFICATION ++ * $PostgreSQL: pgsql/src/backend/storage/lmgr/s_lock.c,v 1.47 2006/10/04 00:29:58 momjian Exp $ ++ * ++ *------------------------------------------------------------------------- ++ */ ++/* #include "postgres.h" -- Removed for APC */ + -+AC_MSG_CHECKING(whether apc needs to get compiler flags from apxs) -+AC_ARG_WITH(apxs, -+[ --with-apxs[=FILE] Get compiler flags from apxs -q. Provide the -+ pathname to the Apache apxs tool; defaults to "apxs".],[ -+ if test "$withval" != "no"; then -+ if test "$withval" = "yes"; then -+ APXS=apxs -+ $APXS -q CFLAGS >/dev/null 2>&1 -+ if test "$?" != "0" && test -x /usr/sbin/apxs; then #SUSE 6.x -+ APXS=/usr/sbin/apxs -+ elif test -x /usr/bin/apxs2; then -+ APXS=/usr/bin/apxs2 -+ elif test -x /usr/sbin/apxs2; then -+ APXS=/usr/sbin/apxs2 -+ fi -+ else -+ PHP_EXPAND_PATH($withval, APXS) -+ fi -+ -+ $APXS -q CFLAGS >/dev/null 2>&1 -+ if test "$?" != "0"; then -+ AC_MSG_RESULT() -+ AC_MSG_RESULT() -+ AC_MSG_RESULT([Sorry, I was not able to successfully run APXS. Possible reasons:]) -+ AC_MSG_RESULT() -+ AC_MSG_RESULT([1. Perl is not installed;]) -+ AC_MSG_RESULT([2. Apache was not compiled with DSO support (--enable-module=so);]) -+ AC_MSG_RESULT([3. 'apxs' is not in your path. Try to use --with-apxs=/path/to/apxs]) -+ AC_MSG_RESULT([The output of $APXS follows]) -+ $APXS -q CFLAGS -+ AC_MSG_ERROR([Aborting]) -+ fi -+ -+ APC_CFLAGS=`$APXS -q CFLAGS` -+ AC_MSG_RESULT(yes) -+ else -+ AC_MSG_RESULT(no) -+ fi -+],[ -+ AC_MSG_RESULT(no) -+]) ++/* -- Added for APC -- */ ++#include "apc.h" ++#ifdef APC_SPIN_LOCKS + -+PHP_ARG_ENABLE(apc, whether to enable APC support, -+[ --enable-apc Enable APC support]) ++#ifdef S_LOCK_TEST ++#include ++#endif ++#ifndef WIN32 ++#include ++#endif ++/* ---- */ + -+AC_MSG_CHECKING(Checking whether we should use mmap) -+AC_ARG_ENABLE(apc-mmap, -+[ --disable-apc-mmap -+ Disable mmap support and use IPC shm instead], -+[ -+ PHP_APC_MMAP=$enableval -+ AC_MSG_RESULT($enableval) -+], [ -+ PHP_APC_MMAP=yes -+ AC_MSG_RESULT(yes) -+]) ++#include ++#ifdef WIN32 ++#include "win32/unistd.h" ++#else ++#include ++#endif + -+AC_MSG_CHECKING(Checking whether we should use semaphore locking instead of fcntl) -+AC_ARG_ENABLE(apc-sem, -+[ --enable-apc-sem -+ Enable semaphore locks instead of fcntl], -+[ -+ PHP_APC_SEM=$enableval -+ AC_MSG_RESULT($enableval) -+], [ -+ PHP_APC_SEM=no -+ AC_MSG_RESULT(no) -+]) ++/* #include "storage/s_lock.h" -- Removed for APC */ ++#include "pgsql_s_lock.h" + -+AC_MSG_CHECKING(Checking whether we should use futex locking) -+AC_ARG_ENABLE(apc-futex, -+[ --enable-apc-futex -+ Enable linux futex based locks EXPERIMENTAL ], -+[ -+ PHP_APC_FUTEX=$enableval -+ AC_MSG_RESULT($enableval) -+], -+[ -+ PHP_APC_FUTEX=no -+ AC_MSG_RESULT(no) -+]) ++static int spins_per_delay = DEFAULT_SPINS_PER_DELAY; + -+if test "$PHP_APC_FUTEX" != "no"; then -+ AC_CHECK_HEADER(linux/futex.h, , [ AC_MSG_ERROR([futex.h not found. Please verify you that are running a 2.5 or older linux kernel and that futex support is enabled.]); ] ) -+fi + -+AC_MSG_CHECKING(Checking whether we should use pthread mutex locking) -+AC_ARG_ENABLE(apc-pthreadmutex, -+[ --enable-apc-pthreadmutex -+ Enable pthread mutex locking EXPERIMENTAL ], -+[ -+ PHP_APC_PTHREADMUTEX=$enableval -+ AC_MSG_RESULT($enableval) -+], -+[ -+ PHP_APC_PTHREADMUTEX=no -+ AC_MSG_RESULT(no) -+]) -+if test "$PHP_APC_PTHREADMUTEX" != "no"; then -+ orig_LIBS="$LIBS" -+ LIBS="$LIBS -lpthread" -+ AC_TRY_RUN( -+ [ -+ #include -+ #include -+ main() { -+ pthread_mutex_t mutex; -+ pthread_mutexattr_t attr; ++/* -- APC specific additions ------------------------------*/ ++/* The following dependencies have been copied from ++ * other pgsql source files. The original locations ++ * have been noted. ++ */ + -+ if(pthread_mutexattr_init(&attr)) { -+ puts("Unable to initialize pthread attributes (pthread_mutexattr_init)."); -+ return -1; -+ } -+ if(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { -+ puts("Unable to set PTHREAD_PROCESS_SHARED (pthread_mutexattr_setpshared), your system may not support shared mutex's which are required. (if you're using threads you should just use the built-in php thread locking)."); -+ return -1; -+ } -+ if(pthread_mutex_init(&mutex, &attr)) { -+ puts("Unable to initialize the mutex (pthread_mutex_init)."); -+ return -1; -+ } -+ if(pthread_mutexattr_destroy(&attr)) { -+ puts("Unable to destroy mutex attributes (pthread_mutexattr_destroy)."); -+ return -1; -+ } -+ if(pthread_mutex_destroy(&mutex)) { -+ puts("Unable to destroy mutex (pthread_mutex_destroy)."); -+ return -1; -+ } ++/* -- from include/c.h -- */ ++#ifndef TRUE ++#define TRUE 1 ++#endif + -+ puts("pthread mutex's are supported!"); -+ return 0; -+ } -+ ], -+ [ dnl -Success- -+ PHP_ADD_LIBRARY(pthread) -+ ], -+ [ dnl -Failure- -+ AC_MSG_ERROR([It doesn't appear that pthread mutex's are supported on your system, please try a different configuration]) -+ ], -+ [ -+ PHP_ADD_LIBRARY(pthread) -+ ] -+ ) -+ LIBS="$orig_LIBS" -+fi ++#ifndef FALSE ++#define FALSE 0 ++#endif + -+AC_MSG_CHECKING(Checking whether we should use spin locks) -+AC_ARG_ENABLE(apc-spinlocks, -+[ --enable-apc-spinlocks -+ Enable spin locks EXPERIMENTAL ], -+[ -+ PHP_APC_SPINLOCKS=$enableval -+ AC_MSG_RESULT($enableval) -+], -+[ -+ PHP_APC_SPINLOCKS=no -+ AC_MSG_RESULT(no) -+]) ++/* -- from include/pg_config_manual.h -- */ ++#define MAX_RANDOM_VALUE (0x7FFFFFFF) + -+if test "$PHP_APC" != "no"; then -+ test "$PHP_APC_MMAP" != "no" && AC_DEFINE(APC_MMAP, 1, [ ]) -+ test "$PHP_APC_SEM" != "no" && AC_DEFINE(APC_SEM_LOCKS, 1, [ ]) -+ test "$PHP_APC_FUTEX" != "no" && AC_DEFINE(APC_FUTEX_LOCKS, 1, [ ]) -+ test "$PHP_APC_PTHREADMUTEX" != "no" && AC_DEFINE(APC_PTHREADMUTEX_LOCKS, 1, [ ]) -+ test "$PHP_APC_SPINLOCKS" != "no" && AC_DEFINE(APC_SPIN_LOCKS, 1, [ ]) ++/* ++ * Max ++ * Return the maximum of two numbers. ++ */ ++#define Max(x, y) ((x) > (y) ? (x) : (y)) + -+ AC_CACHE_CHECK(for union semun, php_cv_semun, -+ [ -+ AC_TRY_COMPILE([ -+#include -+#include -+#include -+ ], [union semun x;], [ -+ php_cv_semun=yes -+ ],[ -+ php_cv_semun=no -+ ]) -+ ]) -+ if test "$php_cv_semun" = "yes"; then -+ AC_DEFINE(HAVE_SEMUN, 1, [ ]) -+ else -+ AC_DEFINE(HAVE_SEMUN, 0, [ ]) -+ fi ++/* -- from include/c.h -- */ ++/* ++ * Min ++ * Return the minimum of two numbers. ++ */ ++#define Min(x, y) ((x) < (y) ? (x) : (y)) + -+ apc_sources="apc.c php_apc.c \ -+ apc_cache.c \ -+ apc_compile.c \ -+ apc_debug.c \ -+ apc_fcntl.c \ -+ apc_main.c \ -+ apc_mmap.c \ -+ apc_sem.c \ -+ apc_shm.c \ -+ apc_futex.c \ -+ apc_pthreadmutex.c \ -+ apc_spin.c \ -+ pgsql_s_lock.c \ -+ apc_sma.c \ -+ apc_stack.c \ -+ apc_zend.c \ -+ apc_rfc1867.c " + -+ PHP_CHECK_LIBRARY(rt, shm_open, [PHP_ADD_LIBRARY(rt,,APC_SHARED_LIBADD)]) -+ PHP_NEW_EXTENSION(apc, $apc_sources, $ext_shared,, \\$(APC_CFLAGS)) -+ PHP_SUBST(APC_SHARED_LIBADD) -+ PHP_SUBST(APC_CFLAGS) -+ AC_DEFINE(HAVE_APC, 1, [ ]) -+fi ++/* -- from backend/port/win32/signal.c -- */ ++/* ++ * pg_usleep --- delay the specified number of microseconds. ++ * ++ * NOTE: although the delay is specified in microseconds, the effective ++ * resolution is only 1/HZ, or 10 milliseconds, on most Unixen. Expect ++ * the requested delay to be rounded up to the next resolution boundary. ++ * ++ * On machines where "long" is 32 bits, the maximum delay is ~2000 seconds. ++ */ ++void ++pg_usleep(long microsec) ++{ ++ if (microsec > 0) ++ { ++#ifndef WIN32 ++ struct timeval delay; ++ ++ delay.tv_sec = microsec / 1000000L; ++ delay.tv_usec = microsec % 1000000L; ++ (void) select(0, NULL, NULL, NULL, &delay); ++#else ++ SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE); ++#endif ++ } ++} + -Index: php-5.2.3/ext/apc/INSTALL -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/INSTALL 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,405 @@ -+Installation Instructions for APC -+--------------------------------- ++/* -- End APC specific additions ------------------------------*/ + -+This version of APC should work on PHP 4.3.0 - 4.4.x and -+5.1.0 - 5.2.x. Yes, that means PHP 5.0.x is no longer -+supported. Upgrade to PHP 5.1.x or 5.2.x and you will -+notice all sorts of performance increases. + -+CVS Instructions -+---------------- -+Building from CVS can be done like this: ++/* ++ * s_lock_stuck() - complain about a stuck spinlock ++ */ ++static void ++s_lock_stuck(volatile slock_t *lock, const char *file, int line TSRMLS_DC) ++{ ++#if defined(S_LOCK_TEST) ++ fprintf(stderr, ++ "\nStuck spinlock (%p) detected at %s:%d.\n", ++ lock, file, line); ++ exit(1); ++#else ++ /* -- Removed for APC ++ elog(PANIC, "stuck spinlock (%p) detected at %s:%d", ++ lock, file, line); ++ */ ++ apc_error("Stuck spinlock (%p) detected" TSRMLS_CC, lock); ++#endif ++} + -+ cvs -d :pserver:cvsread@cvs.php.net:/repository login -+ Password: phpfi -+ cvs -d :pserver:cvsread@cvs.php.net:/repository co pecl/apc -+ cd pecl/apc -+ phpize -+ ./configure --enable-apc-mmap --with-apxs --with-php-config=/usr/local/php/bin/php-config -+ make -+ make install + -+Suggested Configuration (in your php.ini file) -+---------------------------------------------- -+ extension=apc.so -+ apc.enabled=1 -+ apc.shm_segments=1 -+ apc.shm_size=128 -+ apc.ttl=7200 -+ apc.user_ttl=7200 -+ apc.num_files_hint=1024 -+ apc.mmap_file_mask=/tmp/apc.XXXXXX -+ apc.enable_cli=1 ++/* ++ * s_lock(lock) - platform-independent portion of waiting for a spinlock. ++ */ ++void ++s_lock(volatile slock_t *lock, const char *file, int line TSRMLS_DC) ++{ ++ /* ++ * We loop tightly for awhile, then delay using pg_usleep() and try again. ++ * Preferably, "awhile" should be a small multiple of the maximum time we ++ * expect a spinlock to be held. 100 iterations seems about right as an ++ * initial guess. However, on a uniprocessor the loop is a waste of ++ * cycles, while in a multi-CPU scenario it's usually better to spin a bit ++ * longer than to call the kernel, so we try to adapt the spin loop count ++ * depending on whether we seem to be in a uniprocessor or multiprocessor. ++ * ++ * Note: you might think MIN_SPINS_PER_DELAY should be just 1, but you'd ++ * be wrong; there are platforms where that can result in a "stuck ++ * spinlock" failure. This has been seen particularly on Alphas; it seems ++ * that the first TAS after returning from kernel space will always fail ++ * on that hardware. ++ * ++ * Once we do decide to block, we use randomly increasing pg_usleep() ++ * delays. The first delay is 1 msec, then the delay randomly increases to ++ * about one second, after which we reset to 1 msec and start again. The ++ * idea here is that in the presence of heavy contention we need to ++ * increase the delay, else the spinlock holder may never get to run and ++ * release the lock. (Consider situation where spinlock holder has been ++ * nice'd down in priority by the scheduler --- it will not get scheduled ++ * until all would-be acquirers are sleeping, so if we always use a 1-msec ++ * sleep, there is a real possibility of starvation.) But we can't just ++ * clamp the delay to an upper bound, else it would take a long time to ++ * make a reasonable number of tries. ++ * ++ * We time out and declare error after NUM_DELAYS delays (thus, exactly ++ * that many tries). With the given settings, this will usually take 2 or ++ * so minutes. It seems better to fix the total number of tries (and thus ++ * the probability of unintended failure) than to fix the total time ++ * spent. ++ * ++ * The pg_usleep() delays are measured in milliseconds because 1 msec is a ++ * common resolution limit at the OS level for newer platforms. On older ++ * platforms the resolution limit is usually 10 msec, in which case the ++ * total delay before timeout will be a bit more. ++ */ ++#define MIN_SPINS_PER_DELAY 10 ++#define MAX_SPINS_PER_DELAY 1000 ++#define NUM_DELAYS 1000 ++#define MIN_DELAY_MSEC 1 ++#define MAX_DELAY_MSEC 1000 + -+These are fully described at the bottom of this file. ++ int spins = 0; ++ int delays = 0; ++ int cur_delay = 0; ++ ++ while (TAS(lock)) ++ { ++ /* CPU-specific delay each time through the loop */ ++ SPIN_DELAY(); + -+PHP 4 Optimization -+------------------ -+If you are trying to get every little bit of speed out of PHP4+APC, you need -+to tell APC where to find your httpd.h file and also add -DAPC_PHP4_STAT to -+your CPPFLAGS. (if you don't have httpd.h, install the apache_dev package -+for your OS) and do: -+ export CPPFLAGS="-I/usr/include/apache-1.3 -DAPC_PHP4_STAT" (for bash on Debian) -+ setenv CPPFLAGS "-I/usr/include/apache-1.3 -DAPC_PHP4_STAT" (for tsch on Debian) -+and then re-run your configure script. ++ /* Block the process every spins_per_delay tries */ ++ if (++spins >= spins_per_delay) ++ { ++ if (++delays > NUM_DELAYS) ++ s_lock_stuck(lock, file, line TSRMLS_CC); + -+This optimization saves a stat syscall on the main script file. In PHP5 this -+optimization is automatic and doesn't need any special build flags. ++ if (cur_delay == 0) /* first time to delay? */ ++ cur_delay = MIN_DELAY_MSEC; + -+The second thing you are going to want to do to save another syscall is to -+compile using the --with-apxs configure switch. This should work for both -+Apache1 and Apache2. Point it directly at your apxs2 script for Apache2. -+eg. --with-apxs=/usr/local/bin/apxs2 ++ pg_usleep(cur_delay * 1000L); + -++---------------------+ -+| QUICK INSTALL (DSO) | -++---------------------+ ++#if defined(S_LOCK_TEST) ++ fprintf(stdout, "*"); ++ fflush(stdout); ++#endif + -+These instructions assume your PHP installation is located in /usr/local/php and you -+want Apache optimizations (--with-apxs). ++ /* increase delay by a random fraction between 1X and 2X */ ++ cur_delay += (int) (cur_delay * ++ ((double) rand() / (double) MAX_RANDOM_VALUE) + 0.5); ++ /* wrap back to minimum delay when max is exceeded */ ++ if (cur_delay > MAX_DELAY_MSEC) ++ cur_delay = MIN_DELAY_MSEC; + -+$ gunzip -c apc_x.y.tar.gz | tar xf - -+$ cd apc_x.y -+$ /usr/local/php/bin/phpize -+$ ./configure --enable-apc --enable-apc-mmap --with-apxs --with-php-config=/usr/local/php/bin/php-config -+$ make -+$ make install ++ spins = 0; ++ } ++ } + -+You will probably need to run the final command (make install) as root. ++ /* ++ * If we were able to acquire the lock without delaying, it's a good ++ * indication we are in a multiprocessor. If we had to delay, it's a sign ++ * (but not a sure thing) that we are in a uniprocessor. Hence, we ++ * decrement spins_per_delay slowly when we had to delay, and increase it ++ * rapidly when we didn't. It's expected that spins_per_delay will ++ * converge to the minimum value on a uniprocessor and to the maximum ++ * value on a multiprocessor. ++ * ++ * Note: spins_per_delay is local within our current process. We want to ++ * average these observations across multiple backends, since it's ++ * relatively rare for this function to even get entered, and so a single ++ * backend might not live long enough to converge on a good value. That ++ * is handled by the two routines below. ++ */ ++ if (cur_delay == 0) ++ { ++ /* we never had to delay */ ++ if (spins_per_delay < MAX_SPINS_PER_DELAY) ++ spins_per_delay = Min(spins_per_delay + 100, MAX_SPINS_PER_DELAY); ++ } ++ else ++ { ++ if (spins_per_delay > MIN_SPINS_PER_DELAY) ++ spins_per_delay = Max(spins_per_delay - 1, MIN_SPINS_PER_DELAY); ++ } ++} + -+The above sequence of commands will install a .so file in your PHP -+installation extension directory. The output of make install should display -+that path to the screen. + -+Next you must edit your php.ini file, which is normally located in -+/usr/local/php/lib/php.ini, and add the following line: ++#if 0 /* -- APC doesn't use the set_spins_per_delay or update_spins_per_delay -- */ ++/* ++ * Set local copy of spins_per_delay during backend startup. ++ * ++ * NB: this has to be pretty fast as it is called while holding a spinlock ++ */ ++void ++set_spins_per_delay(int shared_spins_per_delay) ++{ ++ spins_per_delay = shared_spins_per_delay; ++} + -+ extension="apc.so" ++/* ++ * Update shared estimate of spins_per_delay during backend exit. ++ * ++ * NB: this has to be pretty fast as it is called while holding a spinlock ++ */ ++int ++update_spins_per_delay(int shared_spins_per_delay) ++{ ++ /* ++ * We use an exponential moving average with a relatively slow adaption ++ * rate, so that noise in any one backend's result won't affect the shared ++ * value too much. As long as both inputs are within the allowed range, ++ * the result must be too, so we need not worry about clamping the result. ++ * ++ * We deliberately truncate rather than rounding; this is so that single ++ * adjustments inside a backend can affect the shared estimate (see the ++ * asymmetric adjustment rules above). ++ */ ++ return (shared_spins_per_delay * 15 + spins_per_delay) / 16; ++} ++#endif + -+Replace "/path/to/php/extensions" with whatever path was displayed when you -+ran make install above. ++/* ++ * Various TAS implementations that cannot live in s_lock.h as no inline ++ * definition exists (yet). ++ * In the future, get rid of tas.[cso] and fold it into this file. ++ * ++ * If you change something here, you will likely need to modify s_lock.h too, ++ * because the definitions for these are split between this file and s_lock.h. ++ */ + -+Then restart your web server and consult the output of phpinfo(). If there is -+an informational section for APC, the installation was successful. + -++------------------------+ -+| QUICK INSTALL (Static) | -++------------------------+ ++#ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */ + -+APC will not successfully compile on all systems as a DSO. If you run into -+problems using the DSO quick install, you can try to compile it statically -+into PHP. (The DSO install is recommended, though.) + -+These instructions assume the current directory is the root of the PHP source -+tree, and that you have already configured PHP by running its bundled -+configure script. ++#if defined(__GNUC__) + -+$ cd ext -+$ gunzip -c apc_x.y.tar.gz | tar xf - -+$ cd .. -+$ ./buildconf -+$ ./config.nice -+$ make -+$ make install ++/* ++ * All the gcc flavors that are not inlined ++ */ + -+Once this is complete, simply restart your web server. You do not need to -+modify your php.ini file to enable APC. + -++-----------------+ -+| VERBOSE INSTALL | -++-----------------+ ++/* ++ * Note: all the if-tests here probably ought to be testing gcc version ++ * rather than platform, but I don't have adequate info to know what to ++ * write. Ideally we'd flush all this in favor of the inline version. ++ */ ++#if defined(__m68k__) && !defined(__linux__) ++/* really means: extern int tas(slock_t* **lock); */ ++static void ++tas_dummy() ++{ ++ __asm__ __volatile__( ++#if defined(__NetBSD__) && defined(__ELF__) ++/* no underscore for label and % for registers */ ++ "\ ++.global tas \n\ ++tas: \n\ ++ movel %sp@(0x4),%a0 \n\ ++ tas %a0@ \n\ ++ beq _success \n\ ++ moveq #-128,%d0 \n\ ++ rts \n\ ++_success: \n\ ++ moveq #0,%d0 \n\ ++ rts \n" ++#else ++ "\ ++.global _tas \n\ ++_tas: \n\ ++ movel sp@(0x4),a0 \n\ ++ tas a0@ \n\ ++ beq _success \n\ ++ moveq #-128,d0 \n\ ++ rts \n\ ++_success: \n\ ++ moveq #0,d0 \n\ ++ rts \n" ++#endif /* __NetBSD__ && __ELF__ */ ++ ); ++} ++#endif /* __m68k__ && !__linux__ */ ++#else /* not __GNUC__ */ + -+These instructions assume your PHP installation is located in /usr/local/php. ++/* ++ * All non gcc ++ */ + -+1. Unpack your distribution file. + -+ You will have downloaded a file named something like apc_x.y.tar.gz. -+ Unzip this file with a command like -+ -+ gunzip apc_x.y.tar.gz -+ -+ Next you have to untar it with -+ -+ tar xvf apc_x.y.tar ++#if defined(sun3) ++static void ++tas_dummy() /* really means: extern int tas(slock_t ++ * *lock); */ ++{ ++ asm("LLA0:"); ++ asm(" .data"); ++ asm(" .text"); ++ asm("|#PROC# 04"); ++ asm(" .globl _tas"); ++ asm("_tas:"); ++ asm("|#PROLOGUE# 1"); ++ asm(" movel sp@(0x4),a0"); ++ asm(" tas a0@"); ++ asm(" beq LLA1"); ++ asm(" moveq #-128,d0"); ++ asm(" rts"); ++ asm("LLA1:"); ++ asm(" moveq #0,d0"); ++ asm(" rts"); ++ asm(" .data"); ++} ++#endif /* sun3 */ ++#endif /* not __GNUC__ */ ++#endif /* HAVE_SPINLOCKS */ + -+ This will create an apc_x.y directory. cd into this new directory: ++#endif /* APC_SPIN_LOCKS */ +diff -Naur a/ext/apc/pgsql_s_lock.h b/ext/apc/pgsql_s_lock.h +--- a/ext/apc/pgsql_s_lock.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/pgsql_s_lock.h 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,928 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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. | ++ +----------------------------------------------------------------------+ ++ | The following code was ported from the PostgreSQL project, please | ++ | see appropriate copyright notices that follow. | ++ | Initial conversion by Brian Shire | ++ +----------------------------------------------------------------------+ + -+ cd apc_x.y ++ */ + -+2. Run phpize. ++/* $Id: pgsql_s_lock.h 307048 2011-01-03 23:53:17Z kalle $ */ + -+ phpize is a script that should have been installed with PHP, and is -+ normally located in /usr/local/php/bin assuming you installed PHP in -+ /usr/local/php. (If you do not have the phpize script, you must reinstall -+ PHP and be sure not to disable PEAR.) ++/*------------------------------------------------------------------------- ++ * ++ * s_lock.h ++ * Hardware-dependent implementation of spinlocks. ++ * ++ * NOTE: none of the macros in this file are intended to be called directly. ++ * Call them through the hardware-independent macros in spin.h. ++ * ++ * The following hardware-dependent macros must be provided for each ++ * supported platform: ++ * ++ * void S_INIT_LOCK(slock_t *lock) ++ * Initialize a spinlock (to the unlocked state). ++ * ++ * void S_LOCK(slock_t *lock) ++ * Acquire a spinlock, waiting if necessary. ++ * Time out and abort() if unable to acquire the lock in a ++ * "reasonable" amount of time --- typically ~ 1 minute. ++ * ++ * void S_UNLOCK(slock_t *lock) ++ * Unlock a previously acquired lock. ++ * ++ * bool S_LOCK_FREE(slock_t *lock) ++ * Tests if the lock is free. Returns TRUE if free, FALSE if locked. ++ * This does *not* change the state of the lock. ++ * ++ * void SPIN_DELAY(void) ++ * Delay operation to occur inside spinlock wait loop. ++ * ++ * Note to implementors: there are default implementations for all these ++ * macros at the bottom of the file. Check if your platform can use ++ * these or needs to override them. ++ * ++ * Usually, S_LOCK() is implemented in terms of an even lower-level macro ++ * TAS(): ++ * ++ * int TAS(slock_t *lock) ++ * Atomic test-and-set instruction. Attempt to acquire the lock, ++ * but do *not* wait. Returns 0 if successful, nonzero if unable ++ * to acquire the lock. ++ * ++ * TAS() is NOT part of the API, and should never be called directly. ++ * ++ * CAUTION: on some platforms TAS() may sometimes report failure to acquire ++ * a lock even when the lock is not locked. For example, on Alpha TAS() ++ * will "fail" if interrupted. Therefore TAS() should always be invoked ++ * in a retry loop, even if you are certain the lock is free. ++ * ++ * ANOTHER CAUTION: be sure that TAS() and S_UNLOCK() represent sequence ++ * points, ie, loads and stores of other values must not be moved across ++ * a lock or unlock. In most cases it suffices to make the operation be ++ * done through a "volatile" pointer. ++ * ++ * On most supported platforms, TAS() uses a tas() function written ++ * in assembly language to execute a hardware atomic-test-and-set ++ * instruction. Equivalent OS-supplied mutex routines could be used too. ++ * ++ * If no system-specific TAS() is available (ie, HAVE_SPINLOCKS is not ++ * defined), then we fall back on an emulation that uses SysV semaphores ++ * (see spin.c). This emulation will be MUCH MUCH slower than a proper TAS() ++ * implementation, because of the cost of a kernel call per lock or unlock. ++ * An old report is that Postgres spends around 40% of its time in semop(2) ++ * when using the SysV semaphore code. ++ * ++ * ++ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group ++ * Portions Copyright (c) 1994, Regents of the University of California ++ * ++ * $PostgreSQL: pgsql/src/include/storage/s_lock.h,v 1.157 2006/06/07 22:24:45 momjian Exp $ ++ * ++ *------------------------------------------------------------------------- ++ */ ++#ifndef S_LOCK_H ++#define S_LOCK_H + -+ Run the phpize command: -+ -+ /usr/local/php/bin/phpize ++/** APC namespace protection ************************************************/ ++/* hack to protect against any possible runtime namespace collisions...*/ ++#define pg_usleep apc_spin_pg_usleep ++#define s_lock apc_spin_s_lock ++#define spins_per_delay apc_spin_spins_per_delay ++/****************************************************************************/ + -+ Its output should resemble this: + -+ autoheader: `config.h.in' is created -+ You should update your `aclocal.m4' by running aclocal. -+ Configuring for: -+ PHP Api Version: 20020918 -+ Zend Module Api No: 20020429 -+ Zend Extension Api No: 20021010 -+ -+ phpize should create a configure script in the current directory. If you -+ get errors instead, you might be missing some required development tools, -+ such as autoconf or libtool. You can try downloading the latest versions -+ of those tools and running phpize again. -+ -+3. Run the configure script. -+ -+ phpize creates a configure script. The only option you need to specify is -+ the location of your php-config script: ++/* #include "storage/pg_sema.h" -- Removed for APC */ + -+ ./configure --enable-apc ++#define HAVE_SPINLOCKS 1 /* -- Added for APC */ + -+ php-config should be located in the same directory as phpize. ++#ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */ + -+ If you prefer to use mmap instead of the default IPC shared memory support, -+ add --enable-apc-mmap to your configure line. + -+ If you prefer to use sysv IPC semaphores over the safer fcntl() locks, add -+ --enable-sem to your configure line. If you don't have a problem -+ with your server segaulting, or any other unnatural accumulation of -+ semaphores on your system, the semaphore based locking is slightly faster. ++#if defined(__GNUC__) || defined(__ICC) ++/************************************************************************* ++ * All the gcc inlines ++ * Gcc consistently defines the CPU as __cpu__. ++ * Other compilers use __cpu or __cpu__ so we test for both in those cases. ++ */ + -+4. Compile and install the files. Simply type: make install ++/*---------- ++ * Standard gcc asm format (assuming "volatile slock_t *lock"): + -+ (You may need to be root in order to install) ++ __asm__ __volatile__( ++ " instruction \n" ++ " instruction \n" ++ " instruction \n" ++: "=r"(_res), "+m"(*lock) // return register, in/out lock value ++: "r"(lock) // lock pointer, in input register ++: "memory", "cc"); // show clobbered registers here + -+ If you encounter errors from libtool or gcc during this step, please -+ contact the project maintainer (dcowgill@php.net). ++ * The output-operands list (after first colon) should always include ++ * "+m"(*lock), whether or not the asm code actually refers to this ++ * operand directly. This ensures that gcc believes the value in the ++ * lock variable is used and set by the asm code. Also, the clobbers ++ * list (after third colon) should always include "memory"; this prevents ++ * gcc from thinking it can cache the values of shared-memory fields ++ * across the asm code. Add "cc" if your asm code changes the condition ++ * code register, and also list any temp registers the code uses. ++ *---------- ++ */ + -+5. Edit your php.ini + -+ make install should have printed a line resembling the following: ++#ifdef __i386__ /* 32-bit i386 */ ++#define HAS_TEST_AND_SET + -+ Installing shared extensions: /path/to/extension/ ++typedef unsigned char slock_t; + -+ Copy the path /path/to/extension/ and add the following line to your -+ php.ini file (normally located in /usr/local/php/lib/php.ini): ++#define TAS(lock) tas(lock) + -+ extension="apc.so" ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ register slock_t _res = 1; + -+ If you don't have a php.ini file in that location, you can create it now. ++ /* ++ * Use a non-locking test before asserting the bus lock. Note that the ++ * extra test appears to be a small loss on some x86 platforms and a small ++ * win on others; it's by no means clear that we should keep it. ++ */ ++ __asm__ __volatile__( ++ " cmpb $0,%1 \n" ++ " jne 1f \n" ++ " lock \n" ++ " xchgb %0,%1 \n" ++ "1: \n" ++: "+q"(_res), "+m"(*lock) ++: ++: "memory", "cc"); ++ return (int) _res; ++} + -+6. Restart the web server and test the installation. ++#define SPIN_DELAY() spin_delay() + -+ Restart your web server now (for apache, it's apachectl restart) and -+ create a small test PHP file in your document root. The file should -+ contain just the following line: ++static __inline__ void ++spin_delay(void) ++{ ++ /* ++ * This sequence is equivalent to the PAUSE instruction ("rep" is ++ * ignored by old IA32 processors if the following instruction is ++ * not a string operation); the IA-32 Architecture Software ++ * Developer's Manual, Vol. 3, Section 7.7.2 describes why using ++ * PAUSE in the inner loop of a spin lock is necessary for good ++ * performance: ++ * ++ * The PAUSE instruction improves the performance of IA-32 ++ * processors supporting Hyper-Threading Technology when ++ * executing spin-wait loops and other routines where one ++ * thread is accessing a shared lock or semaphore in a tight ++ * polling loop. When executing a spin-wait loop, the ++ * processor can suffer a severe performance penalty when ++ * exiting the loop because it detects a possible memory order ++ * violation and flushes the core processor's pipeline. The ++ * PAUSE instruction provides a hint to the processor that the ++ * code sequence is a spin-wait loop. The processor uses this ++ * hint to avoid the memory order violation and prevent the ++ * pipeline flush. In addition, the PAUSE instruction ++ * de-pipelines the spin-wait loop to prevent it from ++ * consuming execution resources excessively. ++ */ ++ __asm__ __volatile__( ++ " rep; nop \n"); ++} + -+ ++#endif /* __i386__ */ + -+ Request that file in a web browser. If there is an entry for APC in the -+ list of installed modules, the installation was successful. + -+ If APC is not listed, consult your web server error log. If it contains an -+ error message saying that it can't load the APC extension, your system -+ might not be able to load shared libraries created with PHP's build -+ system. One alternative would be to compile APC statically into PHP. See -+ the Quick Install (Static) instructions above. ++#ifdef __x86_64__ /* AMD Opteron, Intel EM64T */ ++#define HAS_TEST_AND_SET + -+ You should consult your error log anyway to see if APC generated any -+ errors. On BSD-based platforms, it is typical for APC to be unable to -+ allocate the default-sized shared memory segment. See below for hints on -+ raising your system's shared memory limitations. ++typedef unsigned char slock_t; + -++-----------------+ -+| CONFIGURING APC | -++-----------------+ ++#define TAS(lock) tas(lock) + -+Although the default APC settings are fine for many installations, serious -+users should consider tuning the following parameters: ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ register slock_t _res = 1; + -+ OPTION DESCRIPTION -+ ------------------ -------------------------------------------------- -+ apc.enabled This can be set to 0 to disable APC. This is -+ primarily useful when APC is statically compiled -+ into PHP, since there is no other way to disable -+ it (when compiled as a DSO, the zend_extension -+ line can just be commented-out). -+ (Default: 1) -+ -+ apc.shm_segments The number of shared memory segments to allocate -+ for the compiler cache. If APC is running out of -+ shared memory but you have already set -+ apc.shm_size as high as your system allows, you -+ can try raising this value. Setting this to a -+ value other than 1 has no effect in mmap mode -+ since mmap'ed shm segments don't have size limits. -+ (Default: 1) -+ -+ apc.shm_size The size of each shared memory segment in MB. -+ By default, some systems (including most BSD -+ variants) have very low limits on the size of a -+ shared memory segment. -+ (Default: 30) -+ -+ apc.optimization This option has been deprecated. -+ (Default: 0) -+ -+ apc.num_files_hint A "hint" about the number of distinct source files -+ that will be included or requested on your web -+ server. Set to zero or omit if you're not sure; -+ this setting is mainly useful for sites that have -+ many thousands of source files. -+ (Default: 1000) ++ /* ++ * On Opteron, using a non-locking test before the locking instruction ++ * is a huge loss. On EM64T, it appears to be a wash or small loss, ++ * so we needn't bother to try to distinguish the sub-architectures. ++ */ ++ __asm__ __volatile__( ++ " lock \n" ++ " xchgb %0,%1 \n" ++: "+q"(_res), "+m"(*lock) ++: ++: "memory", "cc"); ++ return (int) _res; ++} + -+ apc.user_entries_hint Just like num_files_hint, a "hint" about the number -+ of distinct user cache variables to store. -+ Set to zero or omit if you're not sure; -+ (Default: 4096) ++#define SPIN_DELAY() spin_delay() + -+ apc.ttl The number of seconds a cache entry is allowed to -+ idle in a slot in case this cache entry slot is -+ needed by another entry. Leaving this at zero -+ means that your cache could potentially fill up -+ with stale entries while newer entries won't be -+ cached. -+ (Default: 0) ++static __inline__ void ++spin_delay(void) ++{ ++ /* ++ * Adding a PAUSE in the spin delay loop is demonstrably a no-op on ++ * Opteron, but it may be of some use on EM64T, so we keep it. ++ */ ++ __asm__ __volatile__( ++ " rep; nop \n"); ++} + -+ apc.user_ttl The number of seconds a user cache entry is allowed -+ to idle in a slot in case this cache entry slot is -+ needed by another entry. Leaving this at zero -+ means that your cache could potentially fill up -+ with stale entries while newer entries won't be -+ cached. -+ (Default: 0) ++#endif /* __x86_64__ */ + + -+ apc.gc_ttl The number of seconds that a cache entry may -+ remain on the garbage-collection list. This value -+ provides a failsafe in the event that a server -+ process dies while executing a cached source file; -+ if that source file is modified, the memory -+ allocated for the old version will not be -+ reclaimed until this TTL reached. Set to zero to -+ disable this feature. -+ (Default: 3600) ++#if defined(__ia64__) || defined(__ia64) /* Intel Itanium */ ++#define HAS_TEST_AND_SET + -+ apc.cache_by_default On by default, but can be set to off and used in -+ conjunction with positive apc.filters so that files -+ are only cached if matched by a positive filter. -+ (Default: On) ++typedef unsigned int slock_t; + -+ apc.filters A comma-separated list of POSIX extended regular -+ expressions. If any pattern matches the source -+ filename, the file will not be cached. Note that -+ the filename used for matching is the one passed -+ to include/require, not the absolute path. If the -+ first character of the expression is a + then the -+ expression will be additive in the sense that any -+ files matched by the expression will be cached, and -+ if the first character is a - then anything matched -+ will not be cached. The - case is the default, so -+ it can be left off. -+ (Default: "") ++#define TAS(lock) tas(lock) + -+ apc.mmap_file_mask If compiled with MMAP support by using --enable-mmap -+ this is the mktemp-style file_mask to pass to the -+ mmap module for determing whether your mmap'ed memory -+ region is going to be file-backed or shared memory -+ backed. For straight file-backed mmap, set it to -+ something like /tmp/apc.XXXXXX (exactly 6 X's). -+ To use POSIX-style shm_open/mmap put a ".shm" -+ somewhere in your mask. eg. "/apc.shm.XXXXXX" -+ You can also set it to "/dev/zero" to use your -+ kernel's /dev/zero interface to anonymous mmap'ed -+ memory. Leaving it undefined will force an -+ anonymous mmap. -+ (Default: "") ++#ifndef __INTEL_COMPILER + -+ apc.slam_defense ** DEPRECATED - Use apc.write_lock instead ** -+ On very busy servers whenever you start the server or -+ modify files you can create a race of many processes -+ all trying to cache the same file at the same time. -+ This option sets the percentage of processes that will -+ skip trying to cache an uncached file. Or think of it -+ as the probability of a single process to skip caching. -+ For example, setting this to 75 would mean that there is -+ a 75% chance that the process will not cache an uncached -+ file. So the higher the setting the greater the defense -+ against cache slams. Setting this to 0 disables this -+ feature. -+ (Default: 0) ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ long int ret; + -+ apc.file_update_protection -+ When you modify a file on a live web server you really -+ should do so in an atomic manner. That is, write to a -+ temporary file and rename (mv) the file into its permanent -+ position when it is ready. Many text editors, cp, tar and -+ other such programs don't do this. This means that there -+ is a chance that a file is accessed (and cached) while it -+ is still being written to. This file_update_protection -+ setting puts a delay on caching brand new files. The -+ default is 2 seconds which means that if the modification -+ timestamp (mtime) on a file shows that it is less than 2 -+ seconds old when it is accessed, it will not be cached. -+ The unfortunate person who accessed this half-written file -+ will still see weirdness, but at least it won't persist. -+ If you are certain you always atomically update your files -+ by using something like rsync which does this correctly, you -+ can turn this protection off by setting it to 0. If you -+ have a system that is flooded with io causing some update -+ procedure to take longer than 2 seconds, you may want to -+ increase this a bit. -+ (Default: 2) ++ __asm__ __volatile__( ++ " xchg4 %0=%1,%2 \n" ++: "=r"(ret), "+m"(*lock) ++: "r"(1) ++: "memory"); ++ return (int) ret; ++} + -+ apc.enable_cli Mostly for testing and debugging. Setting this enables APC -+ for the CLI version of PHP. Normally you wouldn't want to -+ create, populate and tear down the APC cache on every CLI -+ request, but for various test scenarios it is handy to be -+ able to enable APC for the CLI version of APC easily. -+ (Default: 0) ++#else /* __INTEL_COMPILER */ + -+ apc.max_file_size Prevents large files from being cached. -+ (Default: 1M) ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ int ret; + -+ apc.stat Whether to stat the main script file and the fullpath -+ includes. If you turn this off you will need to restart -+ your server in order to update scripts. -+ (Default: 1) ++ ret = _InterlockedExchange(lock,1); /* this is a xchg asm macro */ + -+ apc.write_lock On busy servers when you first start up the server, or when -+ many files are modified, you can end up with all your processes -+ trying to compile and cache the same files. With write_lock -+ enabled, only one process at a time will try to compile an -+ uncached script while the other processes will run uncached -+ instead of sitting around waiting on a lock. -+ (Default: 1) ++ return ret; ++} + -+ apc.report_autofilter Logs any scripts that were automatically excluded from being -+ cached due to early/late binding issues. -+ (Default: 0) ++#endif /* __INTEL_COMPILER */ ++#endif /* __ia64__ || __ia64 */ + -+ apc.rfc1867 RFC1867 File Upload Progress hook handler is only available -+ if you compiled APC against PHP 5.2.0 or later. When enabled -+ any file uploads which includes a field called -+ APC_UPLOAD_PROGRESS before the file field in an upload form -+ will cause APC to automatically create an upload_ -+ user cache entry where is the value of the -+ APC_UPLOAD_PROGRESS form entry. + -+ Note that the file upload tracking is not threadsafe at this -+ point, so new uploads that happen while a previous one is -+ still going will disable the tracking for the previous. -+ (Default: 0) ++#if defined(__arm__) || defined(__arm) ++#define HAS_TEST_AND_SET + -+ apc.localcache This enables a lock-free local process shadow-cache which -+ reduces lock contention when the cache is being written to. -+ (Default: 0) -+ -+ apc.localcache.size The size of the local process shadow-cache, should be set to -+ a sufficently large value, approximately half of num_files_hint. -+ (Default: 512) -+ -+ apc.include_once_override -+ Optimize include_once and require_once calls and avoid the -+ expensive system calls used. -+ (Default: 0) -Index: php-5.2.3/ext/apc/LICENSE -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/LICENSE 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,68 @@ -+-------------------------------------------------------------------- -+ The PHP License, version 3.01 -+Copyright (c) 1999 - 2006 The PHP Group. All rights reserved. -+-------------------------------------------------------------------- ++typedef unsigned char slock_t; + -+Redistribution and use in source and binary forms, with or without -+modification, is permitted provided that the following conditions -+are met: ++#define TAS(lock) tas(lock) + -+ 1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ -+ 2. Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in -+ the documentation and/or other materials provided with the -+ distribution. -+ -+ 3. The name "PHP" must not be used to endorse or promote products -+ derived from this software without prior written permission. For -+ written permission, please contact group@php.net. -+ -+ 4. Products derived from this software may not be called "PHP", nor -+ may "PHP" appear in their name, without prior written permission -+ from group@php.net. You may indicate that your software works in -+ conjunction with PHP by saying "Foo for PHP" instead of calling -+ it "PHP Foo" or "phpfoo" -+ -+ 5. The PHP Group may publish revised and/or new versions of the -+ license from time to time. Each version will be given a -+ distinguishing version number. -+ Once covered code has been published under a particular version -+ of the license, you may always continue to use it under the terms -+ of that version. You may also choose to use such covered code -+ under the terms of any subsequent version of the license -+ published by the PHP Group. No one other than the PHP Group has -+ the right to modify the terms applicable to covered code created -+ under this License. ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ register slock_t _res = 1; + -+ 6. Redistributions of any form whatsoever must retain the following -+ acknowledgment: -+ "This product includes PHP software, freely available from -+ ". ++ __asm__ __volatile__( ++ " swpb %0, %0, [%2] \n" ++: "+r"(_res), "+m"(*lock) ++: "r"(lock) ++: "memory"); ++ return (int) _res; ++} + -+THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND -+ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP -+DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -+OF THE POSSIBILITY OF SUCH DAMAGE. ++#endif /* __arm__ */ + -+-------------------------------------------------------------------- + -+This software consists of voluntary contributions made by many -+individuals on behalf of the PHP Group. ++/* S/390 and S/390x Linux (32- and 64-bit zSeries) */ ++#if defined(__s390__) || defined(__s390x__) ++#define HAS_TEST_AND_SET + -+The PHP Group can be contacted via Email at group@php.net. ++typedef unsigned int slock_t; + -+For more information on the PHP Group and the PHP project, -+please see . ++#define TAS(lock) tas(lock) + -+PHP includes the Zend Engine, freely available at -+. -Index: php-5.2.3/ext/apc/NOTICE -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/NOTICE 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,43 @@ -+This is the NOTICE file that holds acknowledgements and stuff. ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ int _res = 0; + -+The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. -+This extension is being released under the PHP License for complete compliance -+with PHP and to encourage wide-spread use. It is our intention that this -+project be kept open source and that all commercial spin-offs contribute their -+modifications back into the public source-tree. ++ __asm__ __volatile__( ++ " cs %0,%3,0(%2) \n" ++: "+d"(_res), "+m"(*lock) ++: "a"(lock), "d"(1) ++: "memory", "cc"); ++ return _res; ++} + -+Creators: -+ Daniel Cowgill -+ George Schlossnagle ++#endif /* __s390__ || __s390x__ */ + -+PHP5 support and major features by: -+ Arun C. Murthy -+ Gopal Vijayaraghavan -+ Rasmus Lerdorf + -+This software was contributed to PHP by Community Connect Inc. in 2002 -+and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. -+Future revisions and derivatives of this source code must acknowledge -+Community Connect Inc. as the original contributor of this module by -+leaving this note intact in the source code. ++#if defined(__sparc__) /* Sparc */ ++#define HAS_TEST_AND_SET + -+All other licensing and usage conditions are those of the PHP Group. ++typedef unsigned char slock_t; + -+We would like to thank Community Connect Inc. and Yahoo! Inc. for supporting -+this project and providing a challenging and stimulating environment in -+which exciting projects can happen. ++#define TAS(lock) tas(lock) + -+Contributors: -+ Mike Bretz bug fixes, GUI, and lots of work -+ Ricardo Galli changed read-write locks to prefer readers -+ Yann Grossel bug fixes -+ Thies Arntzen bug fixes -+ Sara Golemon optimizer work ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ register slock_t _res; + -+Special Thanks: -+ Florian Baumert help debugging phplib problems -+ Thomas Duffey help debugging inheritance issues -+ Vibol Hou help debugging phplib problems -+ Angel Li diffs for ANSI comment compliance -+ Christian Rishøj help debugging phplib problems -+ Sascha Schumann memory error bug fix -Index: php-5.2.3/ext/apc/pgsql_s_lock.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/pgsql_s_lock.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,481 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2007 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. | -+ +----------------------------------------------------------------------+ -+ | The following code was ported from the PostgreSQL project, please | -+ | see appropriate copyright notices that follow. | -+ | Initial conversion by Brian Shire | -+ +----------------------------------------------------------------------+ ++ /* ++ * See comment in /pg/backend/port/tas/solaris_sparc.s for why this ++ * uses "ldstub", and that file uses "cas". gcc currently generates ++ * sparcv7-targeted binaries, so "cas" use isn't possible. ++ */ ++ __asm__ __volatile__( ++ " ldstub [%2], %0 \n" ++: "=r"(_res), "+m"(*lock) ++: "r"(lock) ++: "memory"); ++ return (int) _res; ++} + -+ */ ++#endif /* __sparc__ */ + -+/* $Id: pgsql_s_lock.c,v 3.2 2007/02/25 05:19:11 shire Exp $ */ + -+/*------------------------------------------------------------------------- -+ * -+ * s_lock.c -+ * Hardware-dependent implementation of spinlocks. -+ * -+ * -+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California -+ * -+ * -+ * IDENTIFICATION -+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/s_lock.c,v 1.47 2006/10/04 00:29:58 momjian Exp $ -+ * -+ *------------------------------------------------------------------------- ++/* PowerPC */ ++#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__) ++#define HAS_TEST_AND_SET ++ ++#if defined(__ppc64__) || defined(__powerpc64__) ++typedef unsigned long slock_t; ++#else ++typedef unsigned int slock_t; ++#endif ++ ++#define TAS(lock) tas(lock) ++/* ++ * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002, ++ * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop. + */ -+/* #include "postgres.h" -- Removed for APC */ ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ slock_t _t; ++ int _res; + -+/* -- Added for APC -- */ -+#include "apc.h" -+#ifdef APC_SPIN_LOCKS ++ __asm__ __volatile__( ++" lwarx %0,0,%3 \n" ++" cmpwi %0,0 \n" ++" bne 1f \n" ++" addi %0,%0,1 \n" ++" stwcx. %0,0,%3 \n" ++" beq 2f \n" ++"1: li %1,1 \n" ++" b 3f \n" ++"2: \n" ++" isync \n" ++" li %1,0 \n" ++"3: \n" + -+#ifdef S_LOCK_TEST -+#include -+#endif -+#ifndef WIN32 -+#include -+#endif -+/* ---- */ ++: "=&r"(_t), "=r"(_res), "+m"(*lock) ++: "r"(lock) ++: "memory", "cc"); ++ return _res; ++} ++ ++/* PowerPC S_UNLOCK is almost standard but requires a "sync" instruction */ ++#define S_UNLOCK(lock) \ ++do \ ++{ \ ++ __asm__ __volatile__ (" sync \n"); \ ++ *((volatile slock_t *) (lock)) = 0; \ ++} while (0) + -+#include -+#include ++#endif /* powerpc */ + -+/* #include "storage/s_lock.h" -- Removed for APC */ -+#include "pgsql_s_lock.h" + -+static int spins_per_delay = DEFAULT_SPINS_PER_DELAY; ++/* Linux Motorola 68k */ ++#if (defined(__mc68000__) || defined(__m68k__)) && defined(__linux__) ++#define HAS_TEST_AND_SET + ++typedef unsigned char slock_t; + -+/* -- APC specific additions ------------------------------*/ -+/* The following dependencies have been copied from -+ * other pgsql source files. The original locations -+ * have been noted. -+ */ ++#define TAS(lock) tas(lock) + -+/* -- from include/c.h -- */ -+#ifndef TRUE -+#define TRUE 1 -+#endif ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ register int rv; + -+#ifndef FALSE -+#define FALSE 0 -+#endif ++ __asm__ __volatile__( ++ " clrl %0 \n" ++ " tas %1 \n" ++ " sne %0 \n" ++: "=d"(rv), "+m"(*lock) ++: ++: "memory", "cc"); ++ return rv; ++} + -+/* -- from include/pg_config_manual.h -- */ -+#define MAX_RANDOM_VALUE (0x7FFFFFFF) ++#endif /* (__mc68000__ || __m68k__) && __linux__ */ + -+/* -+ * Max -+ * Return the maximum of two numbers. -+ */ -+#define Max(x, y) ((x) > (y) ? (x) : (y)) + -+/* -- from include/c.h -- */ +/* -+ * Min -+ * Return the minimum of two numbers. ++ * VAXen -- even multiprocessor ones ++ * (thanks to Tom Ivar Helbekkmo) + */ -+#define Min(x, y) ((x) < (y) ? (x) : (y)) ++#if defined(__vax__) ++#define HAS_TEST_AND_SET + ++typedef unsigned char slock_t; + -+/* -- from backend/port/win32/signal.c -- */ -+/* -+ * pg_usleep --- delay the specified number of microseconds. -+ * -+ * NOTE: although the delay is specified in microseconds, the effective -+ * resolution is only 1/HZ, or 10 milliseconds, on most Unixen. Expect -+ * the requested delay to be rounded up to the next resolution boundary. -+ * -+ * On machines where "long" is 32 bits, the maximum delay is ~2000 seconds. -+ */ -+void -+pg_usleep(long microsec) ++#define TAS(lock) tas(lock) ++ ++static __inline__ int ++tas(volatile slock_t *lock) +{ -+ if (microsec > 0) -+ { -+#ifndef WIN32 -+ struct timeval delay; ++ register int _res; + -+ delay.tv_sec = microsec / 1000000L; -+ delay.tv_usec = microsec % 1000000L; -+ (void) select(0, NULL, NULL, NULL, &delay); -+#else -+ SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE); -+#endif -+ } ++ __asm__ __volatile__( ++ " movl $1, %0 \n" ++ " bbssi $0, (%2), 1f \n" ++ " clrl %0 \n" ++ "1: \n" ++: "=&r"(_res), "+m"(*lock) ++: "r"(lock) ++: "memory"); ++ return _res; +} + -+/* -- End APC specific additions ------------------------------*/ ++#endif /* __vax__ */ + + -+/* -+ * s_lock_stuck() - complain about a stuck spinlock -+ */ -+static void -+s_lock_stuck(volatile slock_t *lock, const char *file, int line) ++#if defined(__ns32k__) /* National Semiconductor 32K */ ++#define HAS_TEST_AND_SET ++ ++typedef unsigned char slock_t; ++ ++#define TAS(lock) tas(lock) ++ ++static __inline__ int ++tas(volatile slock_t *lock) +{ -+#if defined(S_LOCK_TEST) -+ fprintf(stderr, -+ "\nStuck spinlock (%p) detected at %s:%d.\n", -+ lock, file, line); -+ exit(1); -+#else -+ /* -- Removed for APC -+ elog(PANIC, "stuck spinlock (%p) detected at %s:%d", -+ lock, file, line); -+ */ -+ apc_eprint("Stuck spinlock (%p) detected", lock); -+#endif ++ register int _res; ++ ++ __asm__ __volatile__( ++ " sbitb 0, %1 \n" ++ " sfsd %0 \n" ++: "=r"(_res), "+m"(*lock) ++: ++: "memory"); ++ return _res; +} + ++#endif /* __ns32k__ */ ++ + ++#if defined(__alpha) || defined(__alpha__) /* Alpha */ +/* -+ * s_lock(lock) - platform-independent portion of waiting for a spinlock. ++ * Correct multi-processor locking methods are explained in section 5.5.3 ++ * of the Alpha AXP Architecture Handbook, which at this writing can be ++ * found at ftp://ftp.netbsd.org/pub/NetBSD/misc/dec-docs/index.html. ++ * For gcc we implement the handbook's code directly with inline assembler. + */ -+void -+s_lock(volatile slock_t *lock, const char *file, int line) ++#define HAS_TEST_AND_SET ++ ++typedef unsigned long slock_t; ++ ++#define TAS(lock) tas(lock) ++ ++static __inline__ int ++tas(volatile slock_t *lock) +{ -+ /* -+ * We loop tightly for awhile, then delay using pg_usleep() and try again. -+ * Preferably, "awhile" should be a small multiple of the maximum time we -+ * expect a spinlock to be held. 100 iterations seems about right as an -+ * initial guess. However, on a uniprocessor the loop is a waste of -+ * cycles, while in a multi-CPU scenario it's usually better to spin a bit -+ * longer than to call the kernel, so we try to adapt the spin loop count -+ * depending on whether we seem to be in a uniprocessor or multiprocessor. -+ * -+ * Note: you might think MIN_SPINS_PER_DELAY should be just 1, but you'd -+ * be wrong; there are platforms where that can result in a "stuck -+ * spinlock" failure. This has been seen particularly on Alphas; it seems -+ * that the first TAS after returning from kernel space will always fail -+ * on that hardware. -+ * -+ * Once we do decide to block, we use randomly increasing pg_usleep() -+ * delays. The first delay is 1 msec, then the delay randomly increases to -+ * about one second, after which we reset to 1 msec and start again. The -+ * idea here is that in the presence of heavy contention we need to -+ * increase the delay, else the spinlock holder may never get to run and -+ * release the lock. (Consider situation where spinlock holder has been -+ * nice'd down in priority by the scheduler --- it will not get scheduled -+ * until all would-be acquirers are sleeping, so if we always use a 1-msec -+ * sleep, there is a real possibility of starvation.) But we can't just -+ * clamp the delay to an upper bound, else it would take a long time to -+ * make a reasonable number of tries. -+ * -+ * We time out and declare error after NUM_DELAYS delays (thus, exactly -+ * that many tries). With the given settings, this will usually take 2 or -+ * so minutes. It seems better to fix the total number of tries (and thus -+ * the probability of unintended failure) than to fix the total time -+ * spent. -+ * -+ * The pg_usleep() delays are measured in milliseconds because 1 msec is a -+ * common resolution limit at the OS level for newer platforms. On older -+ * platforms the resolution limit is usually 10 msec, in which case the -+ * total delay before timeout will be a bit more. -+ */ -+#define MIN_SPINS_PER_DELAY 10 -+#define MAX_SPINS_PER_DELAY 1000 -+#define NUM_DELAYS 1000 -+#define MIN_DELAY_MSEC 1 -+#define MAX_DELAY_MSEC 1000 ++ register slock_t _res; + -+ int spins = 0; -+ int delays = 0; -+ int cur_delay = 0; -+ -+ while (TAS(lock)) -+ { -+ /* CPU-specific delay each time through the loop */ -+ SPIN_DELAY(); ++ __asm__ __volatile__( ++ " ldq $0, %1 \n" ++ " bne $0, 2f \n" ++ " ldq_l %0, %1 \n" ++ " bne %0, 2f \n" ++ " mov 1, $0 \n" ++ " stq_c $0, %1 \n" ++ " beq $0, 2f \n" ++ " mb \n" ++ " br 3f \n" ++ "2: mov 1, %0 \n" ++ "3: \n" ++: "=&r"(_res), "+m"(*lock) ++: ++: "memory", "0"); ++ return (int) _res; ++} + -+ /* Block the process every spins_per_delay tries */ -+ if (++spins >= spins_per_delay) -+ { -+ if (++delays > NUM_DELAYS) -+ s_lock_stuck(lock, file, line); ++#define S_UNLOCK(lock) \ ++do \ ++{\ ++ __asm__ __volatile__ (" mb \n"); \ ++ *((volatile slock_t *) (lock)) = 0; \ ++} while (0) + -+ if (cur_delay == 0) /* first time to delay? */ -+ cur_delay = MIN_DELAY_MSEC; ++#endif /* __alpha || __alpha__ */ + -+ pg_usleep(cur_delay * 1000L); + -+#if defined(S_LOCK_TEST) -+ fprintf(stdout, "*"); -+ fflush(stdout); -+#endif ++#if defined(__mips__) && !defined(__sgi) /* non-SGI MIPS */ ++/* Note: on SGI we use the OS' mutex ABI, see below */ ++/* Note: R10000 processors require a separate SYNC */ ++#define HAS_TEST_AND_SET ++ ++typedef unsigned int slock_t; ++ ++#define TAS(lock) tas(lock) ++ ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ register volatile slock_t *_l = lock; ++ register int _res; ++ register int _tmp; ++ ++ __asm__ __volatile__( ++ " .set push \n" ++ " .set mips2 \n" ++ " .set noreorder \n" ++ " .set nomacro \n" ++ " ll %0, %2 \n" ++ " or %1, %0, 1 \n" ++ " sc %1, %2 \n" ++ " xori %1, 1 \n" ++ " or %0, %0, %1 \n" ++ " sync \n" ++ " .set pop " ++: "=&r" (_res), "=&r" (_tmp), "+R" (*_l) ++: ++: "memory"); ++ return _res; ++} ++ ++/* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */ ++#define S_UNLOCK(lock) \ ++do \ ++{ \ ++ __asm__ __volatile__( \ ++ " .set push \n" \ ++ " .set mips2 \n" \ ++ " .set noreorder \n" \ ++ " .set nomacro \n" \ ++ " sync \n" \ ++ " .set pop "); \ ++ *((volatile slock_t *) (lock)) = 0; \ ++} while (0) + -+ /* increase delay by a random fraction between 1X and 2X */ -+ cur_delay += (int) (cur_delay * -+ ((double) random() / (double) MAX_RANDOM_VALUE) + 0.5); -+ /* wrap back to minimum delay when max is exceeded */ -+ if (cur_delay > MAX_DELAY_MSEC) -+ cur_delay = MIN_DELAY_MSEC; ++#endif /* __mips__ && !__sgi */ + -+ spins = 0; -+ } -+ } + -+ /* -+ * If we were able to acquire the lock without delaying, it's a good -+ * indication we are in a multiprocessor. If we had to delay, it's a sign -+ * (but not a sure thing) that we are in a uniprocessor. Hence, we -+ * decrement spins_per_delay slowly when we had to delay, and increase it -+ * rapidly when we didn't. It's expected that spins_per_delay will -+ * converge to the minimum value on a uniprocessor and to the maximum -+ * value on a multiprocessor. -+ * -+ * Note: spins_per_delay is local within our current process. We want to -+ * average these observations across multiple backends, since it's -+ * relatively rare for this function to even get entered, and so a single -+ * backend might not live long enough to converge on a good value. That -+ * is handled by the two routines below. -+ */ -+ if (cur_delay == 0) -+ { -+ /* we never had to delay */ -+ if (spins_per_delay < MAX_SPINS_PER_DELAY) -+ spins_per_delay = Min(spins_per_delay + 100, MAX_SPINS_PER_DELAY); -+ } -+ else -+ { -+ if (spins_per_delay > MIN_SPINS_PER_DELAY) -+ spins_per_delay = Max(spins_per_delay - 1, MIN_SPINS_PER_DELAY); -+ } -+} ++/* These live in s_lock.c, but only for gcc */ + + -+#if 0 /* -- APC doesn't use the set_spins_per_delay or update_spins_per_delay -- */ -+/* -+ * Set local copy of spins_per_delay during backend startup. -+ * -+ * NB: this has to be pretty fast as it is called while holding a spinlock -+ */ -+void -+set_spins_per_delay(int shared_spins_per_delay) -+{ -+ spins_per_delay = shared_spins_per_delay; -+} ++#if defined(__m68k__) && !defined(__linux__) /* non-Linux Motorola 68k */ ++#define HAS_TEST_AND_SET + -+/* -+ * Update shared estimate of spins_per_delay during backend exit. -+ * -+ * NB: this has to be pretty fast as it is called while holding a spinlock -+ */ -+int -+update_spins_per_delay(int shared_spins_per_delay) -+{ -+ /* -+ * We use an exponential moving average with a relatively slow adaption -+ * rate, so that noise in any one backend's result won't affect the shared -+ * value too much. As long as both inputs are within the allowed range, -+ * the result must be too, so we need not worry about clamping the result. -+ * -+ * We deliberately truncate rather than rounding; this is so that single -+ * adjustments inside a backend can affect the shared estimate (see the -+ * asymmetric adjustment rules above). -+ */ -+ return (shared_spins_per_delay * 15 + spins_per_delay) / 16; -+} ++typedef unsigned char slock_t; +#endif + -+/* -+ * Various TAS implementations that cannot live in s_lock.h as no inline -+ * definition exists (yet). -+ * In the future, get rid of tas.[cso] and fold it into this file. -+ * -+ * If you change something here, you will likely need to modify s_lock.h too, -+ * because the definitions for these are split between this file and s_lock.h. -+ */ -+ + -+#ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */ ++#endif /* __GNUC__ */ + + -+#if defined(__GNUC__) + +/* -+ * All the gcc flavors that are not inlined ++ * --------------------------------------------------------------------- ++ * Platforms that use non-gcc inline assembly: ++ * --------------------------------------------------------------------- + */ + ++#if !defined(HAS_TEST_AND_SET) /* We didn't trigger above, let's try here */ + -+/* -+ * Note: all the if-tests here probably ought to be testing gcc version -+ * rather than platform, but I don't have adequate info to know what to -+ * write. Ideally we'd flush all this in favor of the inline version. -+ */ -+#if defined(__m68k__) && !defined(__linux__) -+/* really means: extern int tas(slock_t* **lock); */ -+static void -+tas_dummy() -+{ -+ __asm__ __volatile__( -+#if defined(__NetBSD__) && defined(__ELF__) -+/* no underscore for label and % for registers */ -+ "\ -+.global tas \n\ -+tas: \n\ -+ movel %sp@(0x4),%a0 \n\ -+ tas %a0@ \n\ -+ beq _success \n\ -+ moveq #-128,%d0 \n\ -+ rts \n\ -+_success: \n\ -+ moveq #0,%d0 \n\ -+ rts \n" -+#else -+ "\ -+.global _tas \n\ -+_tas: \n\ -+ movel sp@(0x4),a0 \n\ -+ tas a0@ \n\ -+ beq _success \n\ -+ moveq #-128,d0 \n\ -+ rts \n\ -+_success: \n\ -+ moveq #0,d0 \n\ -+ rts \n" -+#endif /* __NetBSD__ && __ELF__ */ -+ ); -+} -+#endif /* __m68k__ && !__linux__ */ -+#else /* not __GNUC__ */ + -+/* -+ * All non gcc -+ */ ++#if defined(USE_UNIVEL_CC) /* Unixware compiler */ ++#define HAS_TEST_AND_SET + ++typedef unsigned char slock_t; + -+#if defined(sun3) -+static void -+tas_dummy() /* really means: extern int tas(slock_t -+ * *lock); */ ++#define TAS(lock) tas(lock) ++ ++asm int ++tas(volatile slock_t *s_lock) +{ -+ asm("LLA0:"); -+ asm(" .data"); -+ asm(" .text"); -+ asm("|#PROC# 04"); -+ asm(" .globl _tas"); -+ asm("_tas:"); -+ asm("|#PROLOGUE# 1"); -+ asm(" movel sp@(0x4),a0"); -+ asm(" tas a0@"); -+ asm(" beq LLA1"); -+ asm(" moveq #-128,d0"); -+ asm(" rts"); -+ asm("LLA1:"); -+ asm(" moveq #0,d0"); -+ asm(" rts"); -+ asm(" .data"); ++/* UNIVEL wants %mem in column 1, so we don't pg_indent this file */ ++%mem s_lock ++ pushl %ebx ++ movl s_lock, %ebx ++ movl $255, %eax ++ lock ++ xchgb %al, (%ebx) ++ popl %ebx +} -+#endif /* sun3 */ -+#endif /* not __GNUC__ */ -+#endif /* HAVE_SPINLOCKS */ -+ + ++#endif /* defined(USE_UNIVEL_CC) */ + -+/*****************************************************************************/ -+#if defined(S_LOCK_TEST) + ++#if defined(__alpha) || defined(__alpha__) /* Tru64 Unix Alpha compiler */ +/* -+ * test program for verifying a port's spinlock support. ++ * The Tru64 compiler doesn't support gcc-style inline asm, but it does ++ * have some builtin functions that accomplish much the same results. ++ * For simplicity, slock_t is defined as long (ie, quadword) on Alpha ++ * regardless of the compiler in use. LOCK_LONG and UNLOCK_LONG only ++ * operate on an int (ie, longword), but that's OK as long as we define ++ * S_INIT_LOCK to zero out the whole quadword. + */ ++#define HAS_TEST_AND_SET + -+struct test_lock_struct -+{ -+ char pad1; -+ slock_t lock; -+ char pad2; -+}; -+ -+volatile struct test_lock_struct test_lock; ++typedef unsigned long slock_t; + -+int -+main() -+{ -+ srandom((unsigned int) time(NULL)); ++#include ++#define S_INIT_LOCK(lock) (*(lock) = 0) ++#define TAS(lock) (__LOCK_LONG_RETRY((lock), 1) == 0) ++#define S_UNLOCK(lock) __UNLOCK_LONG(lock) + -+ test_lock.pad1 = test_lock.pad2 = 0x44; ++#endif /* __alpha || __alpha__ */ + -+ S_INIT_LOCK(&test_lock.lock); + -+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44) -+ { -+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n"); -+ return 1; -+ } ++#if defined(__hppa) || defined(__hppa__) /* HP PA-RISC, GCC and HP compilers */ ++/* ++ * HP's PA-RISC ++ * ++ * See src/backend/port/hpux/tas.c.template for details about LDCWX. Because ++ * LDCWX requires a 16-byte-aligned address, we declare slock_t as a 16-byte ++ * struct. The active word in the struct is whichever has the aligned address; ++ * the other three words just sit at -1. ++ * ++ * When using gcc, we can inline the required assembly code. ++ */ ++#define HAS_TEST_AND_SET + -+ if (!S_LOCK_FREE(&test_lock.lock)) -+ { -+ printf("S_LOCK_TEST: failed, lock not initialized\n"); -+ return 1; -+ } ++typedef struct ++{ ++ int sema[4]; ++} slock_t; + -+ S_LOCK(&test_lock.lock); ++#define TAS_ACTIVE_WORD(lock) ((volatile int *) (((long) (lock) + 15) & ~15)) + -+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44) -+ { -+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n"); -+ return 1; -+ } ++#if defined(__GNUC__) + -+ if (S_LOCK_FREE(&test_lock.lock)) -+ { -+ printf("S_LOCK_TEST: failed, lock not locked\n"); -+ return 1; -+ } ++static __inline__ int ++tas(volatile slock_t *lock) ++{ ++ volatile int *lockword = TAS_ACTIVE_WORD(lock); ++ register int lockval; + -+ S_UNLOCK(&test_lock.lock); ++ __asm__ __volatile__( ++ " ldcwx 0(0,%2),%0 \n" ++: "=r"(lockval), "+m"(*lockword) ++: "r"(lockword) ++: "memory"); ++ return (lockval == 0); ++} + -+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44) -+ { -+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n"); -+ return 1; -+ } ++#endif /* __GNUC__ */ + -+ if (!S_LOCK_FREE(&test_lock.lock)) -+ { -+ printf("S_LOCK_TEST: failed, lock not unlocked\n"); -+ return 1; -+ } ++#define S_UNLOCK(lock) (*TAS_ACTIVE_WORD(lock) = -1) + -+ S_LOCK(&test_lock.lock); ++#define S_INIT_LOCK(lock) \ ++ do { \ ++ volatile slock_t *lock_ = (lock); \ ++ lock_->sema[0] = -1; \ ++ lock_->sema[1] = -1; \ ++ lock_->sema[2] = -1; \ ++ lock_->sema[3] = -1; \ ++ } while (0) + -+ if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44) -+ { -+ printf("S_LOCK_TEST: failed, declared datatype is wrong size\n"); -+ return 1; -+ } ++#define S_LOCK_FREE(lock) (*TAS_ACTIVE_WORD(lock) != 0) + -+ if (S_LOCK_FREE(&test_lock.lock)) -+ { -+ printf("S_LOCK_TEST: failed, lock not re-locked\n"); -+ return 1; -+ } ++#endif /* __hppa || __hppa__ */ + -+ printf("S_LOCK_TEST: this will print %d stars and then\n", NUM_DELAYS); -+ printf(" exit with a 'stuck spinlock' message\n"); -+ printf(" if S_LOCK() and TAS() are working.\n"); -+ fflush(stdout); + -+ s_lock(&test_lock.lock, __FILE__, __LINE__); ++#if defined(__hpux) && defined(__ia64) && !defined(__GNUC__) + -+ printf("S_LOCK_TEST: failed, lock not locked\n"); -+ return 1; -+} ++#define HAS_TEST_AND_SET + -+#endif /* S_LOCK_TEST */ ++typedef unsigned int slock_t; + -+#endif /* APC_SPIN_LOCKS */ -Index: php-5.2.3/ext/apc/pgsql_s_lock.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/pgsql_s_lock.h 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,928 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2007 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. | -+ +----------------------------------------------------------------------+ -+ | The following code was ported from the PostgreSQL project, please | -+ | see appropriate copyright notices that follow. | -+ | Initial conversion by Brian Shire | -+ +----------------------------------------------------------------------+ ++#include ++#define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE) + -+ */ ++#endif /* HPUX on IA64, non gcc */ + -+/* $Id: pgsql_s_lock.h,v 3.3 2007/02/16 21:28:04 shire Exp $ */ + -+/*------------------------------------------------------------------------- -+ * -+ * s_lock.h -+ * Hardware-dependent implementation of spinlocks. -+ * -+ * NOTE: none of the macros in this file are intended to be called directly. -+ * Call them through the hardware-independent macros in spin.h. -+ * -+ * The following hardware-dependent macros must be provided for each -+ * supported platform: -+ * -+ * void S_INIT_LOCK(slock_t *lock) -+ * Initialize a spinlock (to the unlocked state). -+ * -+ * void S_LOCK(slock_t *lock) -+ * Acquire a spinlock, waiting if necessary. -+ * Time out and abort() if unable to acquire the lock in a -+ * "reasonable" amount of time --- typically ~ 1 minute. -+ * -+ * void S_UNLOCK(slock_t *lock) -+ * Unlock a previously acquired lock. -+ * -+ * bool S_LOCK_FREE(slock_t *lock) -+ * Tests if the lock is free. Returns TRUE if free, FALSE if locked. -+ * This does *not* change the state of the lock. -+ * -+ * void SPIN_DELAY(void) -+ * Delay operation to occur inside spinlock wait loop. -+ * -+ * Note to implementors: there are default implementations for all these -+ * macros at the bottom of the file. Check if your platform can use -+ * these or needs to override them. -+ * -+ * Usually, S_LOCK() is implemented in terms of an even lower-level macro -+ * TAS(): -+ * -+ * int TAS(slock_t *lock) -+ * Atomic test-and-set instruction. Attempt to acquire the lock, -+ * but do *not* wait. Returns 0 if successful, nonzero if unable -+ * to acquire the lock. -+ * -+ * TAS() is NOT part of the API, and should never be called directly. -+ * -+ * CAUTION: on some platforms TAS() may sometimes report failure to acquire -+ * a lock even when the lock is not locked. For example, on Alpha TAS() -+ * will "fail" if interrupted. Therefore TAS() should always be invoked -+ * in a retry loop, even if you are certain the lock is free. -+ * -+ * ANOTHER CAUTION: be sure that TAS() and S_UNLOCK() represent sequence -+ * points, ie, loads and stores of other values must not be moved across -+ * a lock or unlock. In most cases it suffices to make the operation be -+ * done through a "volatile" pointer. -+ * -+ * On most supported platforms, TAS() uses a tas() function written -+ * in assembly language to execute a hardware atomic-test-and-set -+ * instruction. Equivalent OS-supplied mutex routines could be used too. -+ * -+ * If no system-specific TAS() is available (ie, HAVE_SPINLOCKS is not -+ * defined), then we fall back on an emulation that uses SysV semaphores -+ * (see spin.c). This emulation will be MUCH MUCH slower than a proper TAS() -+ * implementation, because of the cost of a kernel call per lock or unlock. -+ * An old report is that Postgres spends around 40% of its time in semop(2) -+ * when using the SysV semaphore code. -+ * -+ * -+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group -+ * Portions Copyright (c) 1994, Regents of the University of California ++#if defined(__sgi) /* SGI compiler */ ++/* ++ * SGI IRIX 5 ++ * slock_t is defined as a unsigned long. We use the standard SGI ++ * mutex API. + * -+ * $PostgreSQL: pgsql/src/include/storage/s_lock.h,v 1.157 2006/06/07 22:24:45 momjian Exp $ ++ * The following comment is left for historical reasons, but is probably ++ * not a good idea since the mutex ABI is supported. + * -+ *------------------------------------------------------------------------- ++ * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II ++ * assembly from his NECEWS SVR4 port, but we probably ought to retain this ++ * for the R3000 chips out there. + */ -+#ifndef S_LOCK_H -+#define S_LOCK_H -+ -+/** APC namespace protection ************************************************/ -+/* hack to protect against any possible runtime namespace collisions...*/ -+#define pg_usleep apc_spin_pg_usleep -+#define s_lock apc_spin_s_lock -+#define spins_per_delay apc_spin_spins_per_delay -+/****************************************************************************/ -+ -+ -+/* #include "storage/pg_sema.h" -- Removed for APC */ ++#define HAS_TEST_AND_SET + -+#define HAVE_SPINLOCKS 1 /* -- Added for APC */ ++typedef unsigned long slock_t; + -+#ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */ ++#include "mutex.h" ++#define TAS(lock) (test_and_set(lock,1)) ++#define S_UNLOCK(lock) (test_then_and(lock,0)) ++#define S_INIT_LOCK(lock) (test_then_and(lock,0)) ++#define S_LOCK_FREE(lock) (test_then_add(lock,0) == 0) ++#endif /* __sgi */ + + -+#if defined(__GNUC__) || defined(__ICC) -+/************************************************************************* -+ * All the gcc inlines -+ * Gcc consistently defines the CPU as __cpu__. -+ * Other compilers use __cpu or __cpu__ so we test for both in those cases. ++#if defined(sinix) /* Sinix */ ++/* ++ * SINIX / Reliant UNIX ++ * slock_t is defined as a struct abilock_t, which has a single unsigned long ++ * member. (Basically same as SGI) + */ ++#define HAS_TEST_AND_SET + -+/*---------- -+ * Standard gcc asm format (assuming "volatile slock_t *lock"): -+ -+ __asm__ __volatile__( -+ " instruction \n" -+ " instruction \n" -+ " instruction \n" -+: "=r"(_res), "+m"(*lock) // return register, in/out lock value -+: "r"(lock) // lock pointer, in input register -+: "memory", "cc"); // show clobbered registers here ++#include "abi_mutex.h" ++typedef abilock_t slock_t; + -+ * The output-operands list (after first colon) should always include -+ * "+m"(*lock), whether or not the asm code actually refers to this -+ * operand directly. This ensures that gcc believes the value in the -+ * lock variable is used and set by the asm code. Also, the clobbers -+ * list (after third colon) should always include "memory"; this prevents -+ * gcc from thinking it can cache the values of shared-memory fields -+ * across the asm code. Add "cc" if your asm code changes the condition -+ * code register, and also list any temp registers the code uses. -+ *---------- -+ */ ++#define TAS(lock) (!acquire_lock(lock)) ++#define S_UNLOCK(lock) release_lock(lock) ++#define S_INIT_LOCK(lock) init_lock(lock) ++#define S_LOCK_FREE(lock) (stat_lock(lock) == UNLOCKED) ++#endif /* sinix */ + + -+#ifdef __i386__ /* 32-bit i386 */ ++#if defined(_AIX) /* AIX */ ++/* ++ * AIX (POWER) ++ */ +#define HAS_TEST_AND_SET + -+typedef unsigned char slock_t; ++typedef unsigned int slock_t; + -+#define TAS(lock) tas(lock) ++#define TAS(lock) _check_lock(lock, 0, 1) ++#define S_UNLOCK(lock) _clear_lock(lock, 0) ++#endif /* _AIX */ + -+static __inline__ int -+tas(volatile slock_t *lock) -+{ -+ register slock_t _res = 1; + -+ /* -+ * Use a non-locking test before asserting the bus lock. Note that the -+ * extra test appears to be a small loss on some x86 platforms and a small -+ * win on others; it's by no means clear that we should keep it. -+ */ -+ __asm__ __volatile__( -+ " cmpb $0,%1 \n" -+ " jne 1f \n" -+ " lock \n" -+ " xchgb %0,%1 \n" -+ "1: \n" -+: "+q"(_res), "+m"(*lock) -+: -+: "memory", "cc"); -+ return (int) _res; -+} ++#if defined (nextstep) /* Nextstep */ ++#define HAS_TEST_AND_SET + -+#define SPIN_DELAY() spin_delay() ++typedef struct mutex slock_t; + -+static __inline__ void -+spin_delay(void) -+{ -+ /* -+ * This sequence is equivalent to the PAUSE instruction ("rep" is -+ * ignored by old IA32 processors if the following instruction is -+ * not a string operation); the IA-32 Architecture Software -+ * Developer's Manual, Vol. 3, Section 7.7.2 describes why using -+ * PAUSE in the inner loop of a spin lock is necessary for good -+ * performance: -+ * -+ * The PAUSE instruction improves the performance of IA-32 -+ * processors supporting Hyper-Threading Technology when -+ * executing spin-wait loops and other routines where one -+ * thread is accessing a shared lock or semaphore in a tight -+ * polling loop. When executing a spin-wait loop, the -+ * processor can suffer a severe performance penalty when -+ * exiting the loop because it detects a possible memory order -+ * violation and flushes the core processor's pipeline. The -+ * PAUSE instruction provides a hint to the processor that the -+ * code sequence is a spin-wait loop. The processor uses this -+ * hint to avoid the memory order violation and prevent the -+ * pipeline flush. In addition, the PAUSE instruction -+ * de-pipelines the spin-wait loop to prevent it from -+ * consuming execution resources excessively. -+ */ -+ __asm__ __volatile__( -+ " rep; nop \n"); -+} ++#define APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE 0 /* -- APC: non-blocking lock not available in this case -- */ + -+#endif /* __i386__ */ ++#define S_LOCK(lock) mutex_lock(lock) ++#define S_UNLOCK(lock) mutex_unlock(lock) ++#define S_INIT_LOCK(lock) mutex_init(lock) ++/* For Mach, we have to delve inside the entrails of `struct mutex'. Ick! */ ++#define S_LOCK_FREE(alock) ((alock)->lock == 0) ++#endif /* nextstep */ + + -+#ifdef __x86_64__ /* AMD Opteron, Intel EM64T */ ++/* These are in s_lock.c */ ++ ++ ++#if defined(sun3) /* Sun3 */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; ++#endif + -+#define TAS(lock) tas(lock) + -+static __inline__ int -+tas(volatile slock_t *lock) -+{ -+ register slock_t _res = 1; ++#if defined(__sun) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc)) ++#define HAS_TEST_AND_SET + -+ /* -+ * On Opteron, using a non-locking test before the locking instruction -+ * is a huge loss. On EM64T, it appears to be a wash or small loss, -+ * so we needn't bother to try to distinguish the sub-architectures. -+ */ -+ __asm__ __volatile__( -+ " lock \n" -+ " xchgb %0,%1 \n" -+: "+q"(_res), "+m"(*lock) -+: -+: "memory", "cc"); -+ return (int) _res; -+} ++#if defined(__i386) || defined(__x86_64__) || defined(__sparcv9) || defined(__sparcv8plus) ++typedef unsigned int slock_t; ++#else ++typedef unsigned char slock_t; ++#endif ++ ++extern slock_t pg_atomic_cas(volatile slock_t *lock, slock_t with, ++ slock_t cmp); ++ ++#define TAS(a) (pg_atomic_cas((a), 1, 0) != 0) ++#endif ++ ++ ++#ifdef WIN32_ONLY_COMPILER ++typedef LONG slock_t; ++ ++#define HAS_TEST_AND_SET ++#define TAS(lock) (InterlockedCompareExchange(lock, 1, 0)) + +#define SPIN_DELAY() spin_delay() + -+static __inline__ void ++static __forceinline void +spin_delay(void) +{ -+ /* -+ * Adding a PAUSE in the spin delay loop is demonstrably a no-op on -+ * Opteron, but it may be of some use on EM64T, so we keep it. -+ */ -+ __asm__ __volatile__( -+ " rep; nop \n"); ++ /* See comment for gcc code. Same code, MASM syntax */ ++ __asm rep nop; +} + -+#endif /* __x86_64__ */ ++#endif + ++ ++#endif /* !defined(HAS_TEST_AND_SET) */ + -+#if defined(__ia64__) || defined(__ia64) /* Intel Itanium */ -+#define HAS_TEST_AND_SET + -+typedef unsigned int slock_t; ++/* Blow up if we didn't have any way to do spinlocks */ ++#ifndef HAS_TEST_AND_SET ++/* -- APC: We have better options in APC than this, that should be specified explicitly so just fail out and notify the user -- */ ++#error Spin locking is not available on your platform, please select another locking method (see ./configure --help). ++/* #error PostgreSQL does not have native spinlock support on this platform. To continue the compilation, rerun configure using --disable-spinlocks. However, performance will be poor. Please report this to pgsql-bugs@postgresql.org. */ ++#endif + -+#define TAS(lock) tas(lock) + -+#ifndef __INTEL_COMPILER ++#else /* !HAVE_SPINLOCKS */ + -+static __inline__ int -+tas(volatile slock_t *lock) -+{ -+ long int ret; + -+ __asm__ __volatile__( -+ " xchg4 %0=%1,%2 \n" -+: "=r"(ret), "+m"(*lock) -+: "r"(1) -+: "memory"); -+ return (int) ret; -+} ++/* ++ * Fake spinlock implementation using semaphores --- slow and prone ++ * to fall foul of kernel limits on number of semaphores, so don't use this ++ * unless you must! The subroutines appear in spin.c. ++ */ + -+#else /* __INTEL_COMPILER */ ++/* -- Removed for APC ++typedef PGSemaphoreData slock_t; + -+static __inline__ int -+tas(volatile slock_t *lock) -+{ -+ int ret; ++extern bool s_lock_free_sema(volatile slock_t *lock); ++extern void s_unlock_sema(volatile slock_t *lock); ++extern void s_init_lock_sema(volatile slock_t *lock); ++extern int tas_sema(volatile slock_t *lock); + -+ ret = _InterlockedExchange(lock,1); /* this is a xchg asm macro */ ++#define S_LOCK_FREE(lock) s_lock_free_sema(lock) ++#define S_UNLOCK(lock) s_unlock_sema(lock) ++#define S_INIT_LOCK(lock) s_init_lock_sema(lock) ++#define TAS(lock) tas_sema(lock) ++*/ + -+ return ret; -+} ++#endif /* HAVE_SPINLOCKS */ + -+#endif /* __INTEL_COMPILER */ -+#endif /* __ia64__ || __ia64 */ + ++/* ++ * Default Definitions - override these above as needed. ++ */ + -+#if defined(__arm__) || defined(__arm) -+#define HAS_TEST_AND_SET ++#define APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE 1 /* -- APC: Non-blocking lock available for this case -- */ + -+typedef unsigned char slock_t; ++#if !defined(S_LOCK) ++#define S_LOCK(lock) \ ++ do { \ ++ if (TAS(lock)) \ ++ s_lock((lock), __FILE__, __LINE__ TSRMLS_CC); \ ++ } while (0) ++#endif /* S_LOCK */ + -+#define TAS(lock) tas(lock) ++#if !defined(S_LOCK_FREE) ++#define S_LOCK_FREE(lock) (*(lock) == 0) ++#endif /* S_LOCK_FREE */ + -+static __inline__ int -+tas(volatile slock_t *lock) -+{ -+ register slock_t _res = 1; ++#if !defined(S_UNLOCK) ++#define S_UNLOCK(lock) (*((volatile slock_t *) (lock)) = 0) ++#endif /* S_UNLOCK */ + -+ __asm__ __volatile__( -+ " swpb %0, %0, [%2] \n" -+: "+r"(_res), "+m"(*lock) -+: "r"(lock) -+: "memory"); -+ return (int) _res; -+} ++#if !defined(S_INIT_LOCK) ++#define S_INIT_LOCK(lock) S_UNLOCK(lock) ++#endif /* S_INIT_LOCK */ + -+#endif /* __arm__ */ ++#if !defined(SPIN_DELAY) ++#define SPIN_DELAY() ((void) 0) ++#endif /* SPIN_DELAY */ + ++#if !defined(TAS) ++extern int tas(volatile slock_t *lock); /* in port/.../tas.s, or ++ * s_lock.c */ + -+/* S/390 and S/390x Linux (32- and 64-bit zSeries) */ -+#if defined(__s390__) || defined(__s390x__) -+#define HAS_TEST_AND_SET ++#define TAS(lock) tas(lock) ++#endif /* TAS */ + -+typedef unsigned int slock_t; + -+#define TAS(lock) tas(lock) ++/* ++ * Platform-independent out-of-line support routines ++ */ ++extern void s_lock(volatile slock_t *lock, const char *file, int line TSRMLS_DC); + -+static __inline__ int -+tas(volatile slock_t *lock) -+{ -+ int _res = 0; ++/* Support for dynamic adjustment of spins_per_delay */ ++#define DEFAULT_SPINS_PER_DELAY 100 + -+ __asm__ __volatile__( -+ " cs %0,%3,0(%2) \n" -+: "+d"(_res), "+m"(*lock) -+: "a"(lock), "d"(1) -+: "memory", "cc"); -+ return _res; ++#if 0 /* -- Removed from APC use -- */ ++extern void set_spins_per_delay(int shared_spins_per_delay); ++extern int update_spins_per_delay(int shared_spins_per_delay); ++#endif ++ ++#endif /* S_LOCK_H */ +diff -Naur a/ext/apc/php_apc.c b/ext/apc/php_apc.c +--- a/ext/apc/php_apc.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/php_apc.c 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,1716 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | 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 | ++ | Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Community Connect Inc. in 2002 ++ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. ++ Future revisions and derivatives of this source code must acknowledge ++ Community Connect Inc. as the original contributor of this module by ++ leaving this note intact in the source code. ++ ++ All other licensing and usage conditions are those of the PHP Group. ++ ++ */ ++ ++/* $Id: php_apc.c 325875 2012-05-27 17:15:26Z felipe $ */ ++ ++#include "apc_zend.h" ++#include "apc_cache.h" ++#include "apc_iterator.h" ++#include "apc_main.h" ++#include "apc_sma.h" ++#include "apc_lock.h" ++#include "apc_bin.h" ++#include "php_globals.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "ext/standard/file.h" ++#include "ext/standard/flock_compat.h" ++#ifdef HAVE_SYS_FILE_H ++#include ++#endif ++#include "SAPI.h" ++#include "rfc1867.h" ++#include "php_apc.h" ++#include "ext/standard/md5.h" ++ ++#if HAVE_SIGACTION ++#include "apc_signal.h" ++#endif ++ ++/* {{{ PHP_FUNCTION declarations */ ++PHP_FUNCTION(apc_cache_info); ++PHP_FUNCTION(apc_clear_cache); ++PHP_FUNCTION(apc_sma_info); ++PHP_FUNCTION(apc_store); ++PHP_FUNCTION(apc_fetch); ++PHP_FUNCTION(apc_delete); ++PHP_FUNCTION(apc_delete_file); ++PHP_FUNCTION(apc_compile_file); ++PHP_FUNCTION(apc_define_constants); ++PHP_FUNCTION(apc_load_constants); ++PHP_FUNCTION(apc_add); ++PHP_FUNCTION(apc_inc); ++PHP_FUNCTION(apc_dec); ++PHP_FUNCTION(apc_cas); ++PHP_FUNCTION(apc_bin_dump); ++PHP_FUNCTION(apc_bin_load); ++PHP_FUNCTION(apc_bin_dumpfile); ++PHP_FUNCTION(apc_bin_loadfile); ++PHP_FUNCTION(apc_exists); ++/* }}} */ ++ ++/* {{{ ZEND_DECLARE_MODULE_GLOBALS(apc) */ ++ZEND_DECLARE_MODULE_GLOBALS(apc) ++ ++/* True globals */ ++apc_cache_t* apc_cache = NULL; ++apc_cache_t* apc_user_cache = NULL; ++ ++static void php_apc_init_globals(zend_apc_globals* apc_globals TSRMLS_DC) ++{ ++ apc_globals->filters = NULL; ++ apc_globals->compiled_filters = NULL; ++ apc_globals->initialized = 0; ++ apc_globals->cache_stack = apc_stack_create(0 TSRMLS_CC); ++ apc_globals->cache_by_default = 1; ++ apc_globals->fpstat = 1; ++ apc_globals->canonicalize = 1; ++ apc_globals->stat_ctime = 0; ++ apc_globals->write_lock = 1; ++ apc_globals->slam_defense = 1; ++ apc_globals->report_autofilter = 0; ++ apc_globals->include_once = 0; ++ apc_globals->apc_optimize_function = NULL; ++#ifdef MULTIPART_EVENT_FORMDATA ++ apc_globals->rfc1867 = 0; ++ memset(&(apc_globals->rfc1867_data), 0, sizeof(apc_rfc1867_data)); ++#endif ++ memset(&apc_globals->copied_zvals, 0, sizeof(HashTable)); ++ apc_globals->force_file_update = 0; ++ apc_globals->coredump_unmap = 0; ++ apc_globals->preload_path = NULL; ++ apc_globals->use_request_time = 1; ++ apc_globals->lazy_class_table = NULL; ++ apc_globals->lazy_function_table = NULL; ++ apc_globals->serializer_name = NULL; ++ apc_globals->serializer = NULL; +} + -+#endif /* __s390__ || __s390x__ */ -+ ++static void php_apc_shutdown_globals(zend_apc_globals* apc_globals TSRMLS_DC) ++{ ++ /* deallocate the ignore patterns */ ++ if (apc_globals->filters != NULL) { ++ int i; ++ for (i=0; apc_globals->filters[i] != NULL; i++) { ++ apc_efree(apc_globals->filters[i] TSRMLS_CC); ++ } ++ apc_efree(apc_globals->filters TSRMLS_CC); ++ } + -+#if defined(__sparc__) /* Sparc */ -+#define HAS_TEST_AND_SET ++ /* the stack should be empty */ ++ assert(apc_stack_size(apc_globals->cache_stack) == 0); + -+typedef unsigned char slock_t; ++ /* apc cleanup */ ++ apc_stack_destroy(apc_globals->cache_stack TSRMLS_CC); + -+#define TAS(lock) tas(lock) ++ /* the rest of the globals are cleaned up in apc_module_shutdown() */ ++} + -+static __inline__ int -+tas(volatile slock_t *lock) ++static long apc_atol(const char *str, int str_len) +{ -+ register slock_t _res; ++#if PHP_MAJOR_VERSION >= 6 || PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3 ++ return zend_atol(str, str_len); ++#else ++ /* Re-implement zend_atol() for 5.2.x */ ++ long retval; ++ ++ if (!str_len) { ++ str_len = strlen(str); ++ } ++ ++ retval = strtol(str, NULL, 0); ++ ++ if (str_len > 0) { ++ switch (str[str_len - 1]) { ++ case 'g': ++ case 'G': ++ retval *= 1024; ++ /* break intentionally missing */ ++ case 'm': ++ case 'M': ++ retval *= 1024; ++ /* break intentionally missing */ ++ case 'k': ++ case 'K': ++ retval *= 1024; ++ break; ++ } ++ } + -+ /* -+ * See comment in /pg/backend/port/tas/solaris_sparc.s for why this -+ * uses "ldstub", and that file uses "cas". gcc currently generates -+ * sparcv7-targeted binaries, so "cas" use isn't possible. -+ */ -+ __asm__ __volatile__( -+ " ldstub [%2], %0 \n" -+: "=r"(_res), "+m"(*lock) -+: "r"(lock) -+: "memory"); -+ return (int) _res; ++ return retval; ++#endif +} + -+#endif /* __sparc__ */ ++/* }}} */ + ++/* {{{ PHP_INI */ + -+/* PowerPC */ -+#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__) -+#define HAS_TEST_AND_SET ++static PHP_INI_MH(OnUpdate_filters) /* {{{ */ ++{ ++ APCG(filters) = apc_tokenize(new_value, ',' TSRMLS_CC); ++ return SUCCESS; ++} ++/* }}} */ + -+#if defined(__ppc64__) || defined(__powerpc64__) -+typedef unsigned long slock_t; ++static PHP_INI_MH(OnUpdateShmSegments) /* {{{ */ ++{ ++#if APC_MMAP ++ if(zend_atoi(new_value, new_value_length)!=1) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "apc.shm_segments setting ignored in MMAP mode"); ++ } ++ APCG(shm_segments) = 1; +#else -+typedef unsigned int slock_t; ++ APCG(shm_segments) = zend_atoi(new_value, new_value_length); +#endif ++ return SUCCESS; ++} ++/* }}} */ + -+#define TAS(lock) tas(lock) -+/* -+ * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002, -+ * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop. -+ */ -+static __inline__ int -+tas(volatile slock_t *lock) ++static PHP_INI_MH(OnUpdateShmSize) /* {{{ */ +{ -+ slock_t _t; -+ int _res; -+ -+ __asm__ __volatile__( -+" lwarx %0,0,%3 \n" -+" cmpwi %0,0 \n" -+" bne 1f \n" -+" addi %0,%0,1 \n" -+" stwcx. %0,0,%3 \n" -+" beq 2f \n" -+"1: li %1,1 \n" -+" b 3f \n" -+"2: \n" -+" isync \n" -+" li %1,0 \n" -+"3: \n" ++ long s = apc_atol(new_value, new_value_length); + -+: "=&r"(_t), "=r"(_res), "+m"(*lock) -+: "r"(lock) -+: "memory", "cc"); -+ return _res; -+} ++ if(s <= 0) { ++ return FAILURE; ++ } + -+/* PowerPC S_UNLOCK is almost standard but requires a "sync" instruction */ -+#define S_UNLOCK(lock) \ -+do \ -+{ \ -+ __asm__ __volatile__ (" sync \n"); \ -+ *((volatile slock_t *) (lock)) = 0; \ -+} while (0) ++ if(s < 1048576L) { ++ /* if it's less than 1Mb, they are probably using the old syntax */ ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "apc.shm_size now uses M/G suffixes, please update your ini files"); ++ s = s * 1048576L; ++ } + -+#endif /* powerpc */ ++ APCG(shm_size) = s; + ++ return SUCCESS; ++} ++/* }}} */ + -+/* Linux Motorola 68k */ -+#if (defined(__mc68000__) || defined(__m68k__)) && defined(__linux__) -+#define HAS_TEST_AND_SET ++#ifdef MULTIPART_EVENT_FORMDATA ++static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */ ++{ ++ int tmp; ++ tmp = zend_atoi(new_value, new_value_length); ++ if(tmp < 0) { ++ apc_error("rfc1867_freq must be greater than or equal to zero." TSRMLS_CC); ++ return FAILURE; ++ } ++ if(new_value[new_value_length-1] == '%') { ++ if(tmp > 100) { ++ apc_error("rfc1867_freq cannot be over 100%%" TSRMLS_CC); ++ return FAILURE; ++ } ++ APCG(rfc1867_freq) = tmp / 100.0; ++ } else { ++ APCG(rfc1867_freq) = tmp; ++ } ++ return SUCCESS; ++} ++/* }}} */ ++#endif + -+typedef unsigned char slock_t; ++PHP_INI_BEGIN() ++STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.shm_size", "32M", PHP_INI_SYSTEM, OnUpdateShmSize, shm_size, zend_apc_globals, apc_globals) ++#ifdef ZEND_ENGINE_2_4 ++STD_PHP_INI_ENTRY("apc.shm_strings_buffer", "4M", PHP_INI_SYSTEM, OnUpdateLong, shm_strings_buffer, zend_apc_globals, apc_globals) ++#endif ++STD_PHP_INI_BOOLEAN("apc.include_once_override", "0", PHP_INI_SYSTEM, OnUpdateBool, include_once, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.num_files_hint", "1000", PHP_INI_SYSTEM, OnUpdateLong, num_files_hint, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.user_entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateLong, user_entries_hint, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateLong, gc_ttl, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateLong, ttl, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.user_ttl", "0", PHP_INI_SYSTEM, OnUpdateLong, user_ttl, zend_apc_globals, apc_globals) ++#if APC_MMAP ++STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apc_globals, apc_globals) ++#endif ++PHP_INI_ENTRY("apc.filters", NULL, PHP_INI_SYSTEM, OnUpdate_filters) ++STD_PHP_INI_BOOLEAN("apc.cache_by_default", "1", PHP_INI_ALL, OnUpdateBool, cache_by_default, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.file_update_protection", "2", PHP_INI_SYSTEM, OnUpdateLong,file_update_protection, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.max_file_size", "1M", PHP_INI_SYSTEM, OnUpdateLong, max_file_size, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.stat", "1", PHP_INI_SYSTEM, OnUpdateBool, fpstat, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.canonicalize", "1", PHP_INI_SYSTEM, OnUpdateBool, canonicalize, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.stat_ctime", "0", PHP_INI_SYSTEM, OnUpdateBool, stat_ctime, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.write_lock", "1", PHP_INI_SYSTEM, OnUpdateBool, write_lock, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.slam_defense", "1", PHP_INI_SYSTEM, OnUpdateBool, slam_defense, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.report_autofilter", "0", PHP_INI_SYSTEM, OnUpdateBool, report_autofilter,zend_apc_globals, apc_globals) ++#ifdef MULTIPART_EVENT_FORMDATA ++STD_PHP_INI_BOOLEAN("apc.rfc1867", "0", PHP_INI_SYSTEM, OnUpdateBool, rfc1867, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.rfc1867_prefix", "upload_", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_prefix, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.rfc1867_name", "APC_UPLOAD_PROGRESS", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_name, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.rfc1867_freq", "0", PHP_INI_SYSTEM, OnUpdateRfc1867Freq, rfc1867_freq, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.rfc1867_ttl", "3600", PHP_INI_SYSTEM, OnUpdateLong, rfc1867_ttl, zend_apc_globals, apc_globals) ++#endif ++STD_PHP_INI_BOOLEAN("apc.coredump_unmap", "0", PHP_INI_SYSTEM, OnUpdateBool, coredump_unmap, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.preload_path", (char*)NULL, PHP_INI_SYSTEM, OnUpdateString, preload_path, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.file_md5", "0", PHP_INI_SYSTEM, OnUpdateBool, file_md5, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.use_request_time", "1", PHP_INI_ALL, OnUpdateBool, use_request_time, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.lazy_functions", "0", PHP_INI_SYSTEM, OnUpdateBool, lazy_functions, zend_apc_globals, apc_globals) ++STD_PHP_INI_BOOLEAN("apc.lazy_classes", "0", PHP_INI_SYSTEM, OnUpdateBool, lazy_classes, zend_apc_globals, apc_globals) ++STD_PHP_INI_ENTRY("apc.serializer", "default", PHP_INI_SYSTEM, OnUpdateStringUnempty, serializer_name, zend_apc_globals, apc_globals) ++PHP_INI_END() + -+#define TAS(lock) tas(lock) ++/* }}} */ + -+static __inline__ int -+tas(volatile slock_t *lock) ++/* {{{ PHP_MINFO_FUNCTION(apc) */ ++static PHP_MINFO_FUNCTION(apc) +{ -+ register int rv; -+ -+ __asm__ __volatile__( -+ " clrl %0 \n" -+ " tas %1 \n" -+ " sne %0 \n" -+: "=d"(rv), "+m"(*lock) -+: -+: "memory", "cc"); -+ return rv; -+} ++ apc_serializer_t *serializer = NULL; ++ smart_str names = {0,}; ++ int i; + -+#endif /* (__mc68000__ || __m68k__) && __linux__ */ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "APC Support", APCG(enabled) ? "enabled" : "disabled"); ++ php_info_print_table_row(2, "Version", PHP_APC_VERSION); ++#ifdef __DEBUG_APC__ ++ php_info_print_table_row(2, "APC Debugging", "Enabled"); ++#else ++ php_info_print_table_row(2, "APC Debugging", "Disabled"); ++#endif ++#if APC_MMAP ++ php_info_print_table_row(2, "MMAP Support", "Enabled"); ++ php_info_print_table_row(2, "MMAP File Mask", APCG(mmap_file_mask)); ++#else ++ php_info_print_table_row(2, "MMAP Support", "Disabled"); ++#endif ++ php_info_print_table_row(2, "Locking type", APC_LOCK_TYPE); + ++ for( i = 0, serializer = apc_get_serializers(TSRMLS_C); ++ serializer->name != NULL; ++ serializer++, i++) { ++ if(i != 0) smart_str_appends(&names, ", "); ++ smart_str_appends(&names, serializer->name); ++ } + -+/* -+ * VAXen -- even multiprocessor ones -+ * (thanks to Tom Ivar Helbekkmo) -+ */ -+#if defined(__vax__) -+#define HAS_TEST_AND_SET ++ if(names.c) { ++ smart_str_0(&names); ++ php_info_print_table_row(2, "Serialization Support", names.c); ++ smart_str_free(&names); ++ } else { ++ php_info_print_table_row(2, "Serialization Support", "broken"); ++ } + -+typedef unsigned char slock_t; ++ php_info_print_table_row(2, "Revision", "$Revision: 325875 $"); ++ php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__); ++ php_info_print_table_end(); ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ + -+#define TAS(lock) tas(lock) ++#ifdef MULTIPART_EVENT_FORMDATA ++extern int apc_rfc1867_progress(unsigned int event, void *event_data, void **extra TSRMLS_DC); ++#endif + -+static __inline__ int -+tas(volatile slock_t *lock) ++/* {{{ PHP_MINIT_FUNCTION(apc) */ ++static PHP_MINIT_FUNCTION(apc) +{ -+ register int _res; -+ -+ __asm__ __volatile__( -+ " movl $1, %0 \n" -+ " bbssi $0, (%2), 1f \n" -+ " clrl %0 \n" -+ "1: \n" -+: "=&r"(_res), "+m"(*lock) -+: "r"(lock) -+: "memory"); -+ return _res; -+} ++ ZEND_INIT_MODULE_GLOBALS(apc, php_apc_init_globals, php_apc_shutdown_globals); + -+#endif /* __vax__ */ ++ REGISTER_INI_ENTRIES(); + ++ /* Disable APC in cli mode unless overridden by apc.enable_cli */ ++ if(!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) { ++ APCG(enabled) = 0; ++ } + -+#if defined(__ns32k__) /* National Semiconductor 32K */ -+#define HAS_TEST_AND_SET ++ if (APCG(enabled)) { ++ if(APCG(initialized)) { ++ apc_process_init(module_number TSRMLS_CC); ++ } else { ++ apc_module_init(module_number TSRMLS_CC); ++ apc_zend_init(TSRMLS_C); ++ apc_process_init(module_number TSRMLS_CC); ++#ifdef MULTIPART_EVENT_FORMDATA ++ /* File upload progress tracking */ ++ if(APCG(rfc1867)) { ++ php_rfc1867_callback = apc_rfc1867_progress; ++ } ++#endif ++ apc_iterator_init(module_number TSRMLS_CC); ++ } + -+typedef unsigned char slock_t; ++ zend_register_long_constant("APC_BIN_VERIFY_MD5", sizeof("APC_BIN_VERIFY_MD5"), APC_BIN_VERIFY_MD5, (CONST_CS | CONST_PERSISTENT), module_number TSRMLS_CC); ++ zend_register_long_constant("APC_BIN_VERIFY_CRC32", sizeof("APC_BIN_VERIFY_CRC32"), APC_BIN_VERIFY_CRC32, (CONST_CS | CONST_PERSISTENT), module_number TSRMLS_CC); ++ } + -+#define TAS(lock) tas(lock) ++ return SUCCESS; ++} ++/* }}} */ + -+static __inline__ int -+tas(volatile slock_t *lock) ++/* {{{ PHP_MSHUTDOWN_FUNCTION(apc) */ ++static PHP_MSHUTDOWN_FUNCTION(apc) +{ -+ register int _res; -+ -+ __asm__ __volatile__( -+ " sbitb 0, %1 \n" -+ " sfsd %0 \n" -+: "=r"(_res), "+m"(*lock) -+: -+: "memory"); -+ return _res; ++ if(APCG(enabled)) { ++ apc_process_shutdown(TSRMLS_C); ++ apc_zend_shutdown(TSRMLS_C); ++ apc_module_shutdown(TSRMLS_C); ++#ifndef ZTS ++ php_apc_shutdown_globals(&apc_globals); ++#endif ++#if HAVE_SIGACTION ++ apc_shutdown_signals(TSRMLS_C); ++#endif ++ } ++#ifdef ZTS ++ ts_free_id(apc_globals_id); ++#endif ++ UNREGISTER_INI_ENTRIES(); ++ return SUCCESS; +} ++/* }}} */ + -+#endif /* __ns32k__ */ -+ -+ -+#if defined(__alpha) || defined(__alpha__) /* Alpha */ -+/* -+ * Correct multi-processor locking methods are explained in section 5.5.3 -+ * of the Alpha AXP Architecture Handbook, which at this writing can be -+ * found at ftp://ftp.netbsd.org/pub/NetBSD/misc/dec-docs/index.html. -+ * For gcc we implement the handbook's code directly with inline assembler. -+ */ -+#define HAS_TEST_AND_SET -+ -+typedef unsigned long slock_t; ++/* {{{ PHP_RINIT_FUNCTION(apc) */ ++static PHP_RINIT_FUNCTION(apc) ++{ ++ if(APCG(enabled)) { ++ apc_request_init(TSRMLS_C); + -+#define TAS(lock) tas(lock) ++#if HAVE_SIGACTION ++ apc_set_signals(TSRMLS_C); ++#endif ++ } ++ return SUCCESS; ++} ++/* }}} */ + -+static __inline__ int -+tas(volatile slock_t *lock) ++/* {{{ PHP_RSHUTDOWN_FUNCTION(apc) */ ++static PHP_RSHUTDOWN_FUNCTION(apc) +{ -+ register slock_t _res; -+ -+ __asm__ __volatile__( -+ " ldq $0, %1 \n" -+ " bne $0, 2f \n" -+ " ldq_l %0, %1 \n" -+ " bne %0, 2f \n" -+ " mov 1, $0 \n" -+ " stq_c $0, %1 \n" -+ " beq $0, 2f \n" -+ " mb \n" -+ " br 3f \n" -+ "2: mov 1, %0 \n" -+ "3: \n" -+: "=&r"(_res), "+m"(*lock) -+: -+: "memory", "0"); -+ return (int) _res; ++ if(APCG(enabled)) { ++ apc_request_shutdown(TSRMLS_C); ++ } ++ return SUCCESS; +} ++/* }}} */ + -+#define S_UNLOCK(lock) \ -+do \ -+{\ -+ __asm__ __volatile__ (" mb \n"); \ -+ *((volatile slock_t *) (lock)) = 0; \ -+} while (0) ++/* {{{ proto array apc_cache_info([string type [, bool limited]]) */ ++PHP_FUNCTION(apc_cache_info) ++{ ++ zval* info; ++ char *cache_type; ++ int ct_len; ++ zend_bool limited = 0; + -+#endif /* __alpha || __alpha__ */ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &cache_type, &ct_len, &limited) == FAILURE) { ++ return; ++ } + ++ if(ZEND_NUM_ARGS()) { ++ if(!strcasecmp(cache_type,"user")) { ++ info = apc_cache_info(apc_user_cache, limited TSRMLS_CC); ++ } else if(!strcasecmp(cache_type,"filehits")) { ++#ifdef APC_FILEHITS ++ RETVAL_ZVAL(APCG(filehits), 1, 0); ++ return; ++#else ++ RETURN_FALSE; ++#endif ++ } else { ++ info = apc_cache_info(apc_cache, limited TSRMLS_CC); ++ } ++ } else { ++ info = apc_cache_info(apc_cache, limited TSRMLS_CC); ++ } + -+#if defined(__mips__) && !defined(__sgi) /* non-SGI MIPS */ -+/* Note: on SGI we use the OS' mutex ABI, see below */ -+/* Note: R10000 processors require a separate SYNC */ -+#define HAS_TEST_AND_SET ++ if(!info) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file"); ++ RETURN_FALSE; ++ } + -+typedef unsigned int slock_t; ++ RETURN_ZVAL(info, 0, 1); + -+#define TAS(lock) tas(lock) ++} ++/* }}} */ + -+static __inline__ int -+tas(volatile slock_t *lock) ++/* {{{ proto void apc_clear_cache([string cache]) */ ++PHP_FUNCTION(apc_clear_cache) +{ -+ register volatile slock_t *_l = lock; -+ register int _res; -+ register int _tmp; ++ char *cache_type; ++ int ct_len = 0; + -+ __asm__ __volatile__( -+ " .set push \n" -+ " .set mips2 \n" -+ " .set noreorder \n" -+ " .set nomacro \n" -+ " ll %0, %2 \n" -+ " or %1, %0, 1 \n" -+ " sc %1, %2 \n" -+ " xori %1, 1 \n" -+ " or %0, %0, %1 \n" -+ " sync \n" -+ " .set pop " -+: "=&r" (_res), "=&r" (_tmp), "+R" (*_l) -+: -+: "memory"); -+ return _res; ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache_type, &ct_len) == FAILURE) { ++ return; ++ } ++ ++ if(ct_len) { ++ if(!strcasecmp(cache_type, "user")) { ++ apc_cache_clear(apc_user_cache TSRMLS_CC); ++ RETURN_TRUE; ++ } ++ } ++ apc_cache_clear(apc_cache TSRMLS_CC); ++ RETURN_TRUE; +} ++/* }}} */ + -+/* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */ -+#define S_UNLOCK(lock) \ -+do \ -+{ \ -+ __asm__ __volatile__( \ -+ " .set push \n" \ -+ " .set mips2 \n" \ -+ " .set noreorder \n" \ -+ " .set nomacro \n" \ -+ " sync \n" \ -+ " .set pop "); \ -+ *((volatile slock_t *) (lock)) = 0; \ -+} while (0) ++/* {{{ proto array apc_sma_info([bool limited]) */ ++PHP_FUNCTION(apc_sma_info) ++{ ++ apc_sma_info_t* info; ++ zval* block_lists; ++ int i; ++ zend_bool limited = 0; + -+#endif /* __mips__ && !__sgi */ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &limited) == FAILURE) { ++ return; ++ } + ++ info = apc_sma_info(limited TSRMLS_CC); + -+/* These live in s_lock.c, but only for gcc */ ++ if(!info) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC SMA info available. Perhaps APC is disabled via apc.enabled?"); ++ RETURN_FALSE; ++ } + ++ array_init(return_value); ++ add_assoc_long(return_value, "num_seg", info->num_seg); ++ add_assoc_double(return_value, "seg_size", (double)info->seg_size); ++ add_assoc_double(return_value, "avail_mem", (double)apc_sma_get_avail_mem()); + -+#if defined(__m68k__) && !defined(__linux__) /* non-Linux Motorola 68k */ -+#define HAS_TEST_AND_SET ++ if(limited) { ++ apc_sma_free_info(info TSRMLS_CC); ++ return; ++ } + -+typedef unsigned char slock_t; ++#if ALLOC_DISTRIBUTION ++ { ++ size_t *adist = apc_sma_get_alloc_distribution(); ++ zval* list; ++ ALLOC_INIT_ZVAL(list); ++ array_init(list); ++ for(i=0; i<30; i++) { ++ add_next_index_long(list, adist[i]); ++ } ++ add_assoc_zval(return_value, "adist", list); ++ } +#endif ++ ALLOC_INIT_ZVAL(block_lists); ++ array_init(block_lists); + ++ for (i = 0; i < info->num_seg; i++) { ++ apc_sma_link_t* p; ++ zval* list; + -+#endif /* __GNUC__ */ -+ -+ -+ -+/* -+ * --------------------------------------------------------------------- -+ * Platforms that use non-gcc inline assembly: -+ * --------------------------------------------------------------------- -+ */ -+ -+#if !defined(HAS_TEST_AND_SET) /* We didn't trigger above, let's try here */ -+ -+ -+#if defined(USE_UNIVEL_CC) /* Unixware compiler */ -+#define HAS_TEST_AND_SET ++ ALLOC_INIT_ZVAL(list); ++ array_init(list); + -+typedef unsigned char slock_t; ++ for (p = info->list[i]; p != NULL; p = p->next) { ++ zval* link; + -+#define TAS(lock) tas(lock) ++ ALLOC_INIT_ZVAL(link); ++ array_init(link); + -+asm int -+tas(volatile slock_t *s_lock) -+{ -+/* UNIVEL wants %mem in column 1, so we don't pg_indent this file */ -+%mem s_lock -+ pushl %ebx -+ movl s_lock, %ebx -+ movl $255, %eax -+ lock -+ xchgb %al, (%ebx) -+ popl %ebx ++ add_assoc_long(link, "size", p->size); ++ add_assoc_long(link, "offset", p->offset); ++ add_next_index_zval(list, link); ++ } ++ add_next_index_zval(block_lists, list); ++ } ++ add_assoc_zval(return_value, "block_lists", block_lists); ++ apc_sma_free_info(info TSRMLS_CC); +} ++/* }}} */ + -+#endif /* defined(USE_UNIVEL_CC) */ ++/* {{{ */ ++int _apc_update(char *strkey, int strkey_len, apc_cache_updater_t updater, void* data TSRMLS_DC) ++{ ++ if(!APCG(enabled)) { ++ return 0; ++ } + ++ 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 defined(__alpha) || defined(__alpha__) /* Tru64 Unix Alpha compiler */ -+/* -+ * The Tru64 compiler doesn't support gcc-style inline asm, but it does -+ * have some builtin functions that accomplish much the same results. -+ * For simplicity, slock_t is defined as long (ie, quadword) on Alpha -+ * regardless of the compiler in use. LOCK_LONG and UNLOCK_LONG only -+ * operate on an int (ie, longword), but that's OK as long as we define -+ * S_INIT_LOCK to zero out the whole quadword. -+ */ -+#define HAS_TEST_AND_SET ++ HANDLE_BLOCK_INTERRUPTIONS(); ++ APCG(current_cache) = apc_user_cache; ++ ++ if (!_apc_cache_user_update(apc_user_cache, strkey, strkey_len + 1, updater, data TSRMLS_CC)) { ++ HANDLE_UNBLOCK_INTERRUPTIONS(); ++ return 0; ++ } + -+typedef unsigned long slock_t; ++ APCG(current_cache) = NULL; ++ HANDLE_UNBLOCK_INTERRUPTIONS(); + -+#include -+#define S_INIT_LOCK(lock) (*(lock) = 0) -+#define TAS(lock) (__LOCK_LONG_RETRY((lock), 1) == 0) -+#define S_UNLOCK(lock) __UNLOCK_LONG(lock) ++ return 1; ++} ++/* }}} */ ++ ++/* {{{ _apc_store */ ++int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC) { ++ apc_cache_entry_t *entry; ++ apc_cache_key_t key; ++ time_t t; ++ apc_context_t ctxt={0,}; ++ int ret = 1; + -+#endif /* __alpha || __alpha__ */ ++ t = apc_time(); + ++ if(!APCG(enabled)) return 0; + -+#if defined(__hppa) || defined(__hppa__) /* HP PA-RISC, GCC and HP compilers */ -+/* -+ * HP's PA-RISC -+ * -+ * See src/backend/port/hpux/tas.c.template for details about LDCWX. Because -+ * LDCWX requires a 16-byte-aligned address, we declare slock_t as a 16-byte -+ * struct. The active word in the struct is whichever has the aligned address; -+ * the other three words just sit at -1. -+ * -+ * When using gcc, we can inline the required assembly code. -+ */ -+#define HAS_TEST_AND_SET ++ 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); ++ } + -+typedef struct -+{ -+ int sema[4]; -+} slock_t; ++ HANDLE_BLOCK_INTERRUPTIONS(); + -+#define TAS_ACTIVE_WORD(lock) ((volatile int *) (((long) (lock) + 15) & ~15)) ++ APCG(current_cache) = apc_user_cache; + -+#if defined(__GNUC__) ++ ctxt.pool = apc_pool_create(APC_SMALL_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 0; ++ } ++ ctxt.copy = APC_COPY_IN_USER; ++ ctxt.force_update = 0; + -+static __inline__ int -+tas(volatile slock_t *lock) -+{ -+ volatile int *lockword = TAS_ACTIVE_WORD(lock); -+ register int lockval; ++ if(!ctxt.pool) { ++ ret = 0; ++ goto nocache; ++ } + -+ __asm__ __volatile__( -+ " ldcwx 0(0,%2),%0 \n" -+: "=r"(lockval), "+m"(*lockword) -+: "r"(lockword) -+: "memory"); -+ return (lockval == 0); -+} ++ if (!apc_cache_make_user_key(&key, strkey, strkey_len, t)) { ++ goto freepool; ++ } + -+#endif /* __GNUC__ */ ++ if (apc_cache_is_last_key(apc_user_cache, &key, t TSRMLS_CC)) { ++ goto freepool; ++ } + -+#define S_UNLOCK(lock) (*TAS_ACTIVE_WORD(lock) = -1) ++ if (!(entry = apc_cache_make_user_entry(strkey, strkey_len, val, &ctxt, ttl TSRMLS_CC))) { ++ goto freepool; ++ } + -+#define S_INIT_LOCK(lock) \ -+ do { \ -+ volatile slock_t *lock_ = (lock); \ -+ lock_->sema[0] = -1; \ -+ lock_->sema[1] = -1; \ -+ lock_->sema[2] = -1; \ -+ lock_->sema[3] = -1; \ -+ } while (0) ++ if (!apc_cache_user_insert(apc_user_cache, key, entry, &ctxt, t, exclusive TSRMLS_CC)) { ++freepool: ++ apc_pool_destroy(ctxt.pool TSRMLS_CC); ++ ret = 0; ++ } + -+#define S_LOCK_FREE(lock) (*TAS_ACTIVE_WORD(lock) != 0) ++nocache: + -+#endif /* __hppa || __hppa__ */ ++ APCG(current_cache) = NULL; + ++ HANDLE_UNBLOCK_INTERRUPTIONS(); + -+#if defined(__hpux) && defined(__ia64) && !defined(__GNUC__) ++ return ret; ++} ++/* }}} */ + -+#define HAS_TEST_AND_SET ++/* {{{ apc_store_helper(INTERNAL_FUNCTION_PARAMETERS, const int exclusive) ++ */ ++static void apc_store_helper(INTERNAL_FUNCTION_PARAMETERS, const int exclusive) ++{ ++ zval *key = NULL; ++ zval *val = NULL; ++ long ttl = 0L; ++ HashTable *hash; ++ HashPosition hpos; ++ zval **hentry; ++ char *hkey=NULL; ++ uint hkey_len; ++ ulong hkey_idx; + -+typedef unsigned int slock_t; ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|zl", &key, &val, &ttl) == FAILURE) { ++ return; ++ } + -+#include -+#define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE) ++ if (!key) RETURN_FALSE; + -+#endif /* HPUX on IA64, non gcc */ ++ if (Z_TYPE_P(key) == IS_ARRAY) { ++ hash = Z_ARRVAL_P(key); ++ array_init(return_value); ++ zend_hash_internal_pointer_reset_ex(hash, &hpos); ++ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { ++ zend_hash_get_current_key_ex(hash, &hkey, &hkey_len, &hkey_idx, 0, &hpos); ++ if (hkey) { ++ if(!_apc_store(hkey, hkey_len, *hentry, (unsigned int)ttl, exclusive TSRMLS_CC)) { ++ add_assoc_long_ex(return_value, hkey, hkey_len, -1); /* -1: insertion error */ ++ } ++ hkey = NULL; ++ } else { ++ add_index_long(return_value, hkey_idx, -1); /* -1: insertion error */ ++ } ++ zend_hash_move_forward_ex(hash, &hpos); ++ } ++ return; ++ } else if (Z_TYPE_P(key) == IS_STRING) { ++ if (!val) RETURN_FALSE; ++ if(_apc_store(Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, val, (unsigned int)ttl, exclusive TSRMLS_CC)) ++ RETURN_TRUE; ++ } else { ++ apc_warning("apc_store expects key parameter to be a string or an array of key/value pairs." TSRMLS_CC); ++ } + ++ RETURN_FALSE; ++} ++/* }}} */ + -+#if defined(__sgi) /* SGI compiler */ -+/* -+ * SGI IRIX 5 -+ * slock_t is defined as a unsigned long. We use the standard SGI -+ * mutex API. -+ * -+ * The following comment is left for historical reasons, but is probably -+ * not a good idea since the mutex ABI is supported. -+ * -+ * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II -+ * assembly from his NECEWS SVR4 port, but we probably ought to retain this -+ * for the R3000 chips out there. ++/* {{{ proto int apc_store(mixed key, mixed var [, long ttl ]) + */ -+#define HAS_TEST_AND_SET ++PHP_FUNCTION(apc_store) { ++ apc_store_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); ++} ++/* }}} */ + -+typedef unsigned long slock_t; ++/* {{{ proto int apc_add(mixed key, mixed var [, long ttl ]) ++ */ ++PHP_FUNCTION(apc_add) { ++ apc_store_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); ++} ++/* }}} */ + -+#include "mutex.h" -+#define TAS(lock) (test_and_set(lock,1)) -+#define S_UNLOCK(lock) (test_then_and(lock,0)) -+#define S_INIT_LOCK(lock) (test_then_and(lock,0)) -+#define S_LOCK_FREE(lock) (test_then_add(lock,0) == 0) -+#endif /* __sgi */ ++/* {{{ inc_updater */ + ++struct _inc_update_args { ++ long step; ++ long lval; ++}; + -+#if defined(sinix) /* Sinix */ -+/* -+ * SINIX / Reliant UNIX -+ * slock_t is defined as a struct abilock_t, which has a single unsigned long -+ * member. (Basically same as SGI) -+ */ -+#define HAS_TEST_AND_SET ++static int inc_updater(apc_cache_t* cache, apc_cache_entry_t* entry, void* data) { + -+#include "abi_mutex.h" -+typedef abilock_t slock_t; ++ struct _inc_update_args *args = (struct _inc_update_args*) data; ++ ++ zval* val = entry->data.user.val; + -+#define TAS(lock) (!acquire_lock(lock)) -+#define S_UNLOCK(lock) release_lock(lock) -+#define S_INIT_LOCK(lock) init_lock(lock) -+#define S_LOCK_FREE(lock) (stat_lock(lock) == UNLOCKED) -+#endif /* sinix */ ++ if(Z_TYPE_P(val) == IS_LONG) { ++ Z_LVAL_P(val) += args->step; ++ args->lval = Z_LVAL_P(val); ++ return 1; ++ } + ++ return 0; ++} ++/* }}} */ + -+#if defined(_AIX) /* AIX */ -+/* -+ * AIX (POWER) ++/* {{{ proto long apc_inc(string key [, long step [, bool& success]]) + */ -+#define HAS_TEST_AND_SET ++PHP_FUNCTION(apc_inc) { ++ char *strkey; ++ int strkey_len; ++ struct _inc_update_args args = {1L, -1}; ++ zval *success = NULL; + -+typedef unsigned int slock_t; ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz", &strkey, &strkey_len, &(args.step), &success) == FAILURE) { ++ return; ++ } ++ ++ if (success) { ++ zval_dtor(success); ++ } + -+#define TAS(lock) _check_lock(lock, 0, 1) -+#define S_UNLOCK(lock) _clear_lock(lock, 0) -+#endif /* _AIX */ ++ if(_apc_update(strkey, strkey_len, inc_updater, &args TSRMLS_CC)) { ++ if(success) ZVAL_TRUE(success); ++ RETURN_LONG(args.lval); ++ } ++ ++ if(success) ZVAL_FALSE(success); ++ ++ RETURN_FALSE; ++} ++/* }}} */ + ++/* {{{ proto long apc_dec(string key [, long step [, bool &success]]) ++ */ ++PHP_FUNCTION(apc_dec) { ++ char *strkey; ++ int strkey_len; ++ struct _inc_update_args args = {1L, -1}; ++ zval *success = NULL; + -+#if defined (nextstep) /* Nextstep */ -+#define HAS_TEST_AND_SET ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz", &strkey, &strkey_len, &(args.step), &success) == FAILURE) { ++ return; ++ } ++ ++ if (success) { ++ zval_dtor(success); ++ } + -+typedef struct mutex slock_t; ++ args.step = args.step * -1; + -+#define APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE 0 /* -- APC: non-blocking lock not available in this case -- */ ++ if(_apc_update(strkey, strkey_len, inc_updater, &args TSRMLS_CC)) { ++ if(success) ZVAL_TRUE(success); ++ RETURN_LONG(args.lval); ++ } ++ ++ if(success) ZVAL_FALSE(success); ++ ++ RETURN_FALSE; ++} ++/* }}} */ + -+#define S_LOCK(lock) mutex_lock(lock) -+#define S_UNLOCK(lock) mutex_unlock(lock) -+#define S_INIT_LOCK(lock) mutex_init(lock) -+/* For Mach, we have to delve inside the entrails of `struct mutex'. Ick! */ -+#define S_LOCK_FREE(alock) ((alock)->lock == 0) -+#endif /* nextstep */ ++/* {{{ cas_updater */ ++static int cas_updater(apc_cache_t* cache, apc_cache_entry_t* entry, void* data) { ++ long* vals = ((long*)data); ++ long old = vals[0]; ++ long new = vals[1]; ++ zval* val = entry->data.user.val; + ++ if(Z_TYPE_P(val) == IS_LONG) { ++ if(Z_LVAL_P(val) == old) { ++ Z_LVAL_P(val) = new; ++ return 1; ++ } ++ } + -+/* These are in s_lock.c */ ++ return 0; ++} ++/* }}} */ + ++/* {{{ proto int apc_cas(string key, int old, int new) ++ */ ++PHP_FUNCTION(apc_cas) { ++ char *strkey; ++ int strkey_len; ++ long vals[2]; + -+#if defined(sun3) /* Sun3 */ -+#define HAS_TEST_AND_SET ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll", &strkey, &strkey_len, &vals[0], &vals[1]) == FAILURE) { ++ return; ++ } + -+typedef unsigned char slock_t; -+#endif ++ if(_apc_update(strkey, strkey_len, cas_updater, &vals TSRMLS_CC)) RETURN_TRUE; ++ RETURN_FALSE; ++} ++/* }}} */ + ++void *apc_erealloc_wrapper(void *ptr, size_t size) { ++ return _erealloc(ptr, size, 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); ++} + -+#if defined(__sun) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc)) -+#define HAS_TEST_AND_SET ++/* {{{ proto mixed apc_fetch(mixed key[, bool &success]) ++ */ ++PHP_FUNCTION(apc_fetch) { ++ zval *key; ++ zval *success = NULL; ++ HashTable *hash; ++ HashPosition hpos; ++ zval **hentry; ++ zval *result; ++ zval *result_entry; ++ char *strkey; ++ int strkey_len; ++ apc_cache_entry_t* entry; ++ time_t t; ++ apc_context_t ctxt = {0,}; + -+#if defined(__i386) || defined(__x86_64__) || defined(__sparcv9) || defined(__sparcv8plus) -+typedef unsigned int slock_t; -+#else -+typedef unsigned char slock_t; -+#endif ++ if(!APCG(enabled)) RETURN_FALSE; + -+extern slock_t pg_atomic_cas(volatile slock_t *lock, slock_t with, -+ slock_t cmp); ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &key, &success) == FAILURE) { ++ return; ++ } + -+#define TAS(a) (pg_atomic_cas((a), 1, 0) != 0) -+#endif ++ t = apc_time(); + ++ if (success) { ++ ZVAL_BOOL(success, 0); ++ } + -+#ifdef WIN32_ONLY_COMPILER -+typedef LONG slock_t; ++ ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, NULL, NULL TSRMLS_CC); ++ if (!ctxt.pool) { ++ apc_warning("Unable to allocate memory for pool." TSRMLS_CC); ++ RETURN_FALSE; ++ } ++ ctxt.copy = APC_COPY_OUT_USER; ++ ctxt.force_update = 0; + -+#define HAS_TEST_AND_SET -+#define TAS(lock) (InterlockedCompareExchange(lock, 1, 0)) ++ if(Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) { ++ convert_to_string(key); ++ } ++ ++ if(Z_TYPE_P(key) == IS_STRING) { ++ strkey = Z_STRVAL_P(key); ++ strkey_len = Z_STRLEN_P(key); ++ if(!strkey_len) RETURN_FALSE; ++ entry = apc_cache_user_find(apc_user_cache, strkey, (strkey_len + 1), t TSRMLS_CC); ++ if(entry) { ++ /* deep-copy returned shm zval to emalloc'ed return_value */ ++ apc_cache_fetch_zval(return_value, entry->data.user.val, &ctxt TSRMLS_CC); ++ apc_cache_release(apc_user_cache, entry TSRMLS_CC); ++ } else { ++ goto freepool; ++ } ++ } else if(Z_TYPE_P(key) == IS_ARRAY) { ++ hash = Z_ARRVAL_P(key); ++ MAKE_STD_ZVAL(result); ++ array_init(result); ++ zend_hash_internal_pointer_reset_ex(hash, &hpos); ++ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { ++ if(Z_TYPE_PP(hentry) != IS_STRING) { ++ apc_warning("apc_fetch() expects a string or array of strings." TSRMLS_CC); ++ goto freepool; ++ } ++ entry = apc_cache_user_find(apc_user_cache, Z_STRVAL_PP(hentry), (Z_STRLEN_PP(hentry) + 1), t TSRMLS_CC); ++ if(entry) { ++ /* deep-copy returned shm zval to emalloc'ed return_value */ ++ MAKE_STD_ZVAL(result_entry); ++ apc_cache_fetch_zval(result_entry, entry->data.user.val, &ctxt TSRMLS_CC); ++ apc_cache_release(apc_user_cache, entry TSRMLS_CC); ++ zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1, &result_entry, sizeof(zval*), NULL); ++ } /* don't set values we didn't find */ ++ zend_hash_move_forward_ex(hash, &hpos); ++ } ++ RETVAL_ZVAL(result, 0, 1); ++ } else { ++ apc_warning("apc_fetch() expects a string or array of strings." TSRMLS_CC); ++freepool: ++ apc_pool_destroy(ctxt.pool TSRMLS_CC); ++ RETURN_FALSE; ++ } + -+#define SPIN_DELAY() spin_delay() ++ if (success) { ++ ZVAL_BOOL(success, 1); ++ } + -+static __forceinline void -+spin_delay(void) -+{ -+ /* See comment for gcc code. Same code, MASM syntax */ -+ __asm rep nop; ++ apc_pool_destroy(ctxt.pool TSRMLS_CC); ++ return; +} ++/* }}} */ + -+#endif ++/* {{{ proto mixed apc_exists(mixed key) ++ */ ++PHP_FUNCTION(apc_exists) { ++ zval *key; ++ HashTable *hash; ++ HashPosition hpos; ++ zval **hentry; ++ char *strkey; ++ int strkey_len; ++ apc_cache_entry_t* entry; ++ zval *result; ++ zval *result_entry; ++ time_t t; + -+ -+#endif /* !defined(HAS_TEST_AND_SET) */ ++ if(!APCG(enabled)) RETURN_FALSE; + ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) { ++ return; ++ } + -+/* Blow up if we didn't have any way to do spinlocks */ -+#ifndef HAS_TEST_AND_SET -+/* -- APC: We have better options in APC than this, that should be specified explicitly so just fail out and notify the user -- */ -+#error Spin locking is not available on your platform, please select another locking method (see ./configure --help). -+/* #error PostgreSQL does not have native spinlock support on this platform. To continue the compilation, rerun configure using --disable-spinlocks. However, performance will be poor. Please report this to pgsql-bugs@postgresql.org. */ -+#endif ++ t = apc_time(); + ++ if(Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) { ++ convert_to_string(key); ++ } + -+#else /* !HAVE_SPINLOCKS */ ++ if(Z_TYPE_P(key) == IS_STRING) { ++ strkey = Z_STRVAL_P(key); ++ strkey_len = Z_STRLEN_P(key); ++ if(!strkey_len) RETURN_FALSE; ++ entry = apc_cache_user_exists(apc_user_cache, strkey, strkey_len + 1, t TSRMLS_CC); ++ if(entry) { ++ RETURN_TRUE; ++ } ++ } else if(Z_TYPE_P(key) == IS_ARRAY) { ++ hash = Z_ARRVAL_P(key); ++ MAKE_STD_ZVAL(result); ++ array_init(result); ++ zend_hash_internal_pointer_reset_ex(hash, &hpos); ++ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { ++ if(Z_TYPE_PP(hentry) != IS_STRING) { ++ apc_warning("apc_exists() expects a string or array of strings." TSRMLS_CC); ++ RETURN_FALSE; ++ } + ++ entry = apc_cache_user_exists(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1, t TSRMLS_CC); ++ if(entry) { ++ MAKE_STD_ZVAL(result_entry); ++ ZVAL_BOOL(result_entry, 1); ++ zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1, &result_entry, sizeof(zval*), NULL); ++ } /* don't set values we didn't find */ ++ zend_hash_move_forward_ex(hash, &hpos); ++ } ++ RETURN_ZVAL(result, 0, 1); ++ } else { ++ apc_warning("apc_exists() expects a string or array of strings." TSRMLS_CC); ++ } + -+/* -+ * Fake spinlock implementation using semaphores --- slow and prone -+ * to fall foul of kernel limits on number of semaphores, so don't use this -+ * unless you must! The subroutines appear in spin.c. -+ */ ++ RETURN_FALSE; ++} ++/* }}} */ + -+/* -- Removed for APC -+typedef PGSemaphoreData slock_t; + -+extern bool s_lock_free_sema(volatile slock_t *lock); -+extern void s_unlock_sema(volatile slock_t *lock); -+extern void s_init_lock_sema(volatile slock_t *lock); -+extern int tas_sema(volatile slock_t *lock); ++/* {{{ proto mixed apc_delete(mixed keys) ++ */ ++PHP_FUNCTION(apc_delete) { ++ zval *keys; + -+#define S_LOCK_FREE(lock) s_lock_free_sema(lock) -+#define S_UNLOCK(lock) s_unlock_sema(lock) -+#define S_INIT_LOCK(lock) s_init_lock_sema(lock) -+#define TAS(lock) tas_sema(lock) -+*/ ++ if(!APCG(enabled)) RETURN_FALSE; + -+#endif /* HAVE_SPINLOCKS */ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &keys) == FAILURE) { ++ return; ++ } + ++ if (Z_TYPE_P(keys) == IS_STRING) { ++ if (!Z_STRLEN_P(keys)) RETURN_FALSE; ++ if(apc_cache_user_delete(apc_user_cache, Z_STRVAL_P(keys), (Z_STRLEN_P(keys) + 1) TSRMLS_CC)) { ++ RETURN_TRUE; ++ } else { ++ RETURN_FALSE; ++ } ++ } else if (Z_TYPE_P(keys) == IS_ARRAY) { ++ HashTable *hash = Z_ARRVAL_P(keys); ++ HashPosition hpos; ++ zval **hentry; ++ array_init(return_value); ++ zend_hash_internal_pointer_reset_ex(hash, &hpos); ++ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { ++ if(Z_TYPE_PP(hentry) != IS_STRING) { ++ apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance." TSRMLS_CC); ++ add_next_index_zval(return_value, *hentry); ++ Z_ADDREF_PP(hentry); ++ } else if(apc_cache_user_delete(apc_user_cache, Z_STRVAL_PP(hentry), (Z_STRLEN_PP(hentry) + 1) TSRMLS_CC) != 1) { ++ add_next_index_zval(return_value, *hentry); ++ Z_ADDREF_PP(hentry); ++ } ++ zend_hash_move_forward_ex(hash, &hpos); ++ } ++ return; ++ } else if (Z_TYPE_P(keys) == IS_OBJECT) { ++ if (apc_iterator_delete(keys TSRMLS_CC)) { ++ RETURN_TRUE; ++ } else { ++ RETURN_FALSE; ++ } ++ } else { ++ apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance." TSRMLS_CC); ++ } ++} ++/* }}} */ + -+/* -+ * Default Definitions - override these above as needed. ++/* {{{ proto mixed apc_delete_file(mixed keys) ++ * Deletes the given files from the opcode cache. ++ * Accepts a string, array of strings, or APCIterator object. ++ * Returns True/False, or for an Array an Array of failed files. + */ ++PHP_FUNCTION(apc_delete_file) { ++ zval *keys; + -+#define APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE 1 /* -- APC: Non-blocking lock available for this case -- */ ++ if(!APCG(enabled)) RETURN_FALSE; + -+#if !defined(S_LOCK) -+#define S_LOCK(lock) \ -+ do { \ -+ if (TAS(lock)) \ -+ s_lock((lock), __FILE__, __LINE__); \ -+ } while (0) -+#endif /* S_LOCK */ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &keys) == FAILURE) { ++ return; ++ } + -+#if !defined(S_LOCK_FREE) -+#define S_LOCK_FREE(lock) (*(lock) == 0) -+#endif /* S_LOCK_FREE */ ++ if (Z_TYPE_P(keys) == IS_STRING) { ++ if (!Z_STRLEN_P(keys)) RETURN_FALSE; ++ if(apc_cache_delete(apc_cache, Z_STRVAL_P(keys), Z_STRLEN_P(keys) + 1 TSRMLS_CC) != 1) { ++ RETURN_FALSE; ++ } else { ++ RETURN_TRUE; ++ } ++ } else if (Z_TYPE_P(keys) == IS_ARRAY) { ++ HashTable *hash = Z_ARRVAL_P(keys); ++ HashPosition hpos; ++ zval **hentry; ++ array_init(return_value); ++ zend_hash_internal_pointer_reset_ex(hash, &hpos); ++ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { ++ if(Z_TYPE_PP(hentry) != IS_STRING) { ++ apc_warning("apc_delete_file() expects a string, array of strings, or APCIterator instance." TSRMLS_CC); ++ add_next_index_zval(return_value, *hentry); ++ Z_ADDREF_PP(hentry); ++ } else if(apc_cache_delete(apc_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1 TSRMLS_CC) != 1) { ++ add_next_index_zval(return_value, *hentry); ++ Z_ADDREF_PP(hentry); ++ } ++ zend_hash_move_forward_ex(hash, &hpos); ++ } ++ return; ++ } else if (Z_TYPE_P(keys) == IS_OBJECT) { ++ if (apc_iterator_delete(keys TSRMLS_CC)) { ++ RETURN_TRUE; ++ } else { ++ RETURN_FALSE; ++ } ++ } else { ++ apc_warning("apc_delete_file() expects a string, array of strings, or APCIterator instance." TSRMLS_CC); ++ } ++} ++/* }}} */ + -+#if !defined(S_UNLOCK) -+#define S_UNLOCK(lock) (*((volatile slock_t *) (lock)) = 0) -+#endif /* S_UNLOCK */ ++static void _apc_define_constants(zval *constants, zend_bool case_sensitive TSRMLS_DC) { ++ char *const_key; ++ unsigned int const_key_len; ++ zval **entry; ++ HashPosition pos; + -+#if !defined(S_INIT_LOCK) -+#define S_INIT_LOCK(lock) S_UNLOCK(lock) -+#endif /* S_INIT_LOCK */ ++ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(constants), &pos); ++ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(constants), (void**)&entry, &pos) == SUCCESS) { ++ zend_constant c; ++ int key_type; ++ ulong num_key; + -+#if !defined(SPIN_DELAY) -+#define SPIN_DELAY() ((void) 0) -+#endif /* SPIN_DELAY */ ++ key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(constants), &const_key, &const_key_len, &num_key, 0, &pos); ++ if(key_type != HASH_KEY_IS_STRING) { ++ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); ++ continue; ++ } ++ switch(Z_TYPE_PP(entry)) { ++ case IS_LONG: ++ case IS_DOUBLE: ++ case IS_STRING: ++ case IS_BOOL: ++ case IS_RESOURCE: ++ case IS_NULL: ++ break; ++ default: ++ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); ++ continue; ++ } ++ c.value = **entry; ++ zval_copy_ctor(&c.value); ++ c.flags = case_sensitive; ++ c.name = zend_strndup(const_key, const_key_len); ++ c.name_len = const_key_len; ++ c.module_number = PHP_USER_CONSTANT; ++ zend_register_constant(&c TSRMLS_CC); + -+#if !defined(TAS) -+extern int tas(volatile slock_t *lock); /* in port/.../tas.s, or -+ * s_lock.c */ ++ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); ++ } ++} + -+#define TAS(lock) tas(lock) -+#endif /* TAS */ ++/* {{{ proto mixed apc_define_constants(string key, array constants [, bool case_sensitive]) ++ */ ++PHP_FUNCTION(apc_define_constants) { ++ char *strkey; ++ int strkey_len; ++ zval *constants = NULL; ++ zend_bool case_sensitive = 1; ++ int argc = ZEND_NUM_ARGS(); ++ ++ if (zend_parse_parameters(argc TSRMLS_CC, "sa|b", &strkey, &strkey_len, &constants, &case_sensitive) == FAILURE) { ++ return; ++ } + ++ if(!strkey_len) RETURN_FALSE; + -+/* -+ * Platform-independent out-of-line support routines ++ _apc_define_constants(constants, case_sensitive TSRMLS_CC); ++ if(_apc_store(strkey, strkey_len + 1, constants, 0, 0 TSRMLS_CC)) RETURN_TRUE; ++ RETURN_FALSE; ++} /* }}} */ ++ ++/* {{{ proto mixed apc_load_constants(string key [, bool case_sensitive]) + */ -+extern void s_lock(volatile slock_t *lock, const char *file, int line); ++PHP_FUNCTION(apc_load_constants) { ++ char *strkey; ++ int strkey_len; ++ apc_cache_entry_t* entry; ++ time_t t; ++ zend_bool case_sensitive = 1; + -+/* Support for dynamic adjustment of spins_per_delay */ -+#define DEFAULT_SPINS_PER_DELAY 100 ++ if(!APCG(enabled)) RETURN_FALSE; ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &strkey, &strkey_len, &case_sensitive) == FAILURE) { ++ return; ++ } + -+#if 0 /* -- Removed from APC use -- */ -+extern void set_spins_per_delay(int shared_spins_per_delay); -+extern int update_spins_per_delay(int shared_spins_per_delay); -+#endif ++ if(!strkey_len) RETURN_FALSE; + -+#endif /* S_LOCK_H */ -Index: php-5.2.3/ext/apc/php_apc.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/php_apc.c 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,957 @@ -+/* -+ +----------------------------------------------------------------------+ -+ | APC | -+ +----------------------------------------------------------------------+ -+ | Copyright (c) 2006 The PHP Group | -+ +----------------------------------------------------------------------+ -+ | This source file is subject to version 3.01 of the PHP license, | -+ | that is bundled with this package in the file LICENSE, and is | -+ | available through the world-wide-web at the following url: | -+ | http://www.php.net/license/3_01.txt | -+ | If you did not receive a copy of the PHP license and are unable to | -+ | obtain it through the world-wide-web, please send a note to | -+ | license@php.net so we can mail you a copy immediately. | -+ +----------------------------------------------------------------------+ -+ | Authors: Daniel Cowgill | -+ | Rasmus Lerdorf | -+ +----------------------------------------------------------------------+ ++ t = apc_time(); + -+ 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. ++ entry = apc_cache_user_find(apc_user_cache, strkey, (strkey_len + 1), t TSRMLS_CC); + -+ All other licensing and usage conditions are those of the PHP Group. ++ if(entry) { ++ _apc_define_constants(entry->data.user.val, case_sensitive TSRMLS_CC); ++ apc_cache_release(apc_user_cache, entry TSRMLS_CC); ++ RETURN_TRUE; ++ } else { ++ RETURN_FALSE; ++ } ++} ++/* }}} */ + ++/* {{{ proto mixed apc_compile_file(mixed filenames [, bool atomic]) + */ ++PHP_FUNCTION(apc_compile_file) { ++ zval *file; ++ zend_file_handle file_handle; ++ zend_op_array *op_array; ++ char** filters = NULL; ++ zend_bool cache_by_default = 1; ++ HashTable cg_function_table, cg_class_table; ++ HashTable *cg_orig_function_table, *cg_orig_class_table, *eg_orig_function_table, *eg_orig_class_table; ++ apc_cache_entry_t** cache_entries; ++ apc_cache_key_t* keys; ++ zend_op_array **op_arrays; ++ time_t t; ++ zval **hentry; ++ HashPosition hpos; ++ int i=0, c=0; ++ int *rval=NULL; ++ int count=0; ++ zend_bool atomic=1; ++ apc_context_t ctxt = {0,}; ++ zend_execute_data *orig_current_execute_data; ++ int atomic_fail; + -+/* $Id: php_apc.c,v 3.140 2007/03/28 07:14:54 gopalv Exp $ */ ++ if(!APCG(enabled)) RETURN_FALSE; + -+#include "apc_zend.h" -+#include "apc_cache.h" -+#include "apc_main.h" -+#include "apc_sma.h" -+#include "apc_lock.h" -+#include "php_globals.h" -+#include "php_ini.h" -+#include "ext/standard/info.h" -+#include "SAPI.h" -+#include "rfc1867.h" -+#include "php_apc.h" -+#if PHP_API_VERSION <= 20020918 -+#if HAVE_APACHE -+#ifdef APC_PHP4_STAT -+#undef XtOffsetOf -+#include "httpd.h" -+#endif -+#endif -+#endif ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &file, &atomic) == FAILURE) { ++ return; ++ } + -+/* {{{ PHP_FUNCTION declarations */ -+PHP_FUNCTION(apc_cache_info); -+PHP_FUNCTION(apc_clear_cache); -+PHP_FUNCTION(apc_sma_info); -+PHP_FUNCTION(apc_store); -+PHP_FUNCTION(apc_fetch); -+PHP_FUNCTION(apc_delete); -+PHP_FUNCTION(apc_compile_file); -+PHP_FUNCTION(apc_define_constants); -+PHP_FUNCTION(apc_load_constants); -+PHP_FUNCTION(apc_add); -+/* }}} */ ++ if (Z_TYPE_P(file) != IS_ARRAY && Z_TYPE_P(file) != IS_STRING) { ++ apc_warning("apc_compile_file argument must be a string or an array of strings" TSRMLS_CC); ++ RETURN_FALSE; ++ } + -+/* {{{ ZEND_DECLARE_MODULE_GLOBALS(apc) */ -+ZEND_DECLARE_MODULE_GLOBALS(apc) ++ HANDLE_BLOCK_INTERRUPTIONS(); ++ APCG(current_cache) = apc_cache; + -+/* True globals */ -+apc_cache_t* apc_cache = NULL; -+apc_cache_t* apc_user_cache = NULL; -+void* apc_compiled_filters = NULL; ++ /* reset filters and cache_by_default */ ++ filters = APCG(filters); ++ APCG(filters) = NULL; + -+static void php_apc_init_globals(zend_apc_globals* apc_globals TSRMLS_DC) -+{ -+ apc_globals->filters = NULL; -+ apc_globals->initialized = 0; -+ apc_globals->cache_stack = apc_stack_create(0); -+ apc_globals->cache_by_default = 1; -+ apc_globals->slam_defense = 0; -+ apc_globals->mem_size_ptr = NULL; -+ apc_globals->fpstat = 1; -+ apc_globals->stat_ctime = 0; -+ apc_globals->write_lock = 1; -+ apc_globals->report_autofilter = 0; -+ apc_globals->apc_optimize_function = NULL; -+#ifdef MULTIPART_EVENT_FORMDATA -+ apc_globals->rfc1867 = 0; -+#endif -+ apc_globals->copied_zvals = NULL; -+#ifdef ZEND_ENGINE_2 -+ apc_globals->reserved_offset = -1; -+#endif -+ apc_globals->localcache = 0; -+ apc_globals->localcache_size = 0; -+ apc_globals->lcache = NULL; -+} ++ cache_by_default = APCG(cache_by_default); ++ APCG(cache_by_default) = 1; + -+static void php_apc_shutdown_globals(zend_apc_globals* apc_globals TSRMLS_DC) -+{ -+ /* deallocate the ignore patterns */ -+ if (apc_globals->filters != NULL) { -+ int i; -+ for (i=0; apc_globals->filters[i] != NULL; i++) { -+ apc_efree(apc_globals->filters[i]); ++ /* Replace function/class tables to avoid namespace conflicts */ ++ zend_hash_init_ex(&cg_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); ++ cg_orig_function_table = CG(function_table); ++ CG(function_table) = &cg_function_table; ++ zend_hash_init_ex(&cg_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); ++ cg_orig_class_table = CG(class_table); ++ CG(class_table) = &cg_class_table; ++ eg_orig_function_table = EG(function_table); ++ EG(function_table) = CG(function_table); ++ eg_orig_class_table = EG(class_table); ++ EG(class_table) = CG(class_table); ++ APCG(force_file_update) = 1; ++ ++ /* Compile the file(s), loading it into the cache */ ++ if (Z_TYPE_P(file) == IS_STRING) { ++ file_handle.type = ZEND_HANDLE_FILENAME; ++ file_handle.filename = Z_STRVAL_P(file); ++ file_handle.free_filename = 0; ++ file_handle.opened_path = NULL; ++ ++ orig_current_execute_data = EG(current_execute_data); ++ zend_try { ++ op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC); ++ } zend_catch { ++ EG(current_execute_data) = orig_current_execute_data; ++ EG(in_execution) = 1; ++ CG(unclean_shutdown) = 0; ++ apc_warning("Error compiling %s in apc_compile_file." TSRMLS_CC, file_handle.filename); ++ op_array = NULL; ++ } zend_end_try(); ++ if(op_array != NULL) { ++ /* Free up everything */ ++ destroy_op_array(op_array TSRMLS_CC); ++ efree(op_array); ++ RETVAL_TRUE; ++ } else { ++ RETVAL_FALSE; + } -+ apc_efree(apc_globals->filters); -+ } ++ zend_destroy_file_handle(&file_handle TSRMLS_CC); + -+ /* the stack should be empty */ -+ assert(apc_stack_size(apc_globals->cache_stack) == 0); ++ } else { /* IS_ARRAY */ + -+ /* apc cleanup */ -+ apc_stack_destroy(apc_globals->cache_stack); ++ array_init(return_value); + -+ /* the rest of the globals are cleaned up in apc_module_shutdown() */ -+} ++ t = apc_time(); + -+/* }}} */ ++ op_arrays = ecalloc(Z_ARRVAL_P(file)->nNumOfElements, sizeof(zend_op_array*)); ++ cache_entries = ecalloc(Z_ARRVAL_P(file)->nNumOfElements, sizeof(apc_cache_entry_t*)); ++ keys = ecalloc(Z_ARRVAL_P(file)->nNumOfElements, sizeof(apc_cache_key_t)); ++ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(file), &hpos); ++ while(zend_hash_get_current_data_ex(Z_ARRVAL_P(file), (void**)&hentry, &hpos) == SUCCESS) { ++ if (Z_TYPE_PP(hentry) != IS_STRING) { ++ apc_warning("apc_compile_file array values must be strings, aborting." TSRMLS_CC); ++ break; ++ } ++ file_handle.type = ZEND_HANDLE_FILENAME; ++ file_handle.filename = Z_STRVAL_PP(hentry); ++ file_handle.free_filename = 0; ++ file_handle.opened_path = NULL; ++ ++ if (!apc_cache_make_file_key(&(keys[i]), file_handle.filename, PG(include_path), t TSRMLS_CC)) { ++ add_assoc_long(return_value, Z_STRVAL_PP(hentry), -1); /* -1: compilation error */ ++ apc_warning("Error compiling %s in apc_compile_file." TSRMLS_CC, file_handle.filename); ++ break; ++ } + -+/* {{{ PHP_INI */ ++ if (keys[i].type == APC_CACHE_KEY_FPFILE) { ++ keys[i].data.fpfile.fullpath = estrndup(keys[i].data.fpfile.fullpath, keys[i].data.fpfile.fullpath_len); ++ } else if (keys[i].type == APC_CACHE_KEY_USER) { ++ keys[i].data.user.identifier = estrndup(keys[i].data.user.identifier, keys[i].data.user.identifier_len); ++ } + -+static PHP_INI_MH(OnUpdate_filters) /* {{{ */ -+{ -+ APCG(filters) = apc_tokenize(new_value, ','); -+ return SUCCESS; -+} -+/* }}} */ ++ orig_current_execute_data = EG(current_execute_data); ++ zend_try { ++ if (apc_compile_cache_entry(&keys[i], &file_handle, ZEND_INCLUDE, t, &op_arrays[i], &cache_entries[i] TSRMLS_CC) != SUCCESS) { ++ op_arrays[i] = NULL; ++ cache_entries[i] = NULL; ++ add_assoc_long(return_value, Z_STRVAL_PP(hentry), -2); /* -2: input or cache insertion error */ ++ apc_warning("Error compiling %s in apc_compile_file." TSRMLS_CC, file_handle.filename); ++ } ++ } zend_catch { ++ EG(current_execute_data) = orig_current_execute_data; ++ EG(in_execution) = 1; ++ CG(unclean_shutdown) = 0; ++ op_arrays[i] = NULL; ++ cache_entries[i] = NULL; ++ add_assoc_long(return_value, Z_STRVAL_PP(hentry), -1); /* -1: compilation error */ ++ apc_warning("Error compiling %s in apc_compile_file." TSRMLS_CC, file_handle.filename); ++ } zend_end_try(); ++ ++ zend_destroy_file_handle(&file_handle TSRMLS_CC); ++ if(op_arrays[i] != NULL) { ++ count++; ++ } + -+static PHP_INI_MH(OnUpdateShmSegments) /* {{{ */ -+{ -+#if APC_MMAP -+ if(atoi(new_value)!=1) { -+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "apc.shm_segments setting ignored in MMAP mode"); -+ } -+ APCG(shm_segments) = 1; -+#else -+ APCG(shm_segments) = atoi(new_value); -+#endif -+ return SUCCESS; -+} -+/* }}} */ ++ /* clean out the function/class tables */ ++ zend_hash_clean(&cg_function_table); ++ zend_hash_clean(&cg_class_table); + ++ zend_hash_move_forward_ex(Z_ARRVAL_P(file), &hpos); ++ i++; ++ } + -+#ifdef ZEND_ENGINE_2 -+#define OnUpdateInt OnUpdateLong -+#endif ++ /* atomically update the cache if no errors or not atomic */ ++ ctxt.copy = APC_COPY_IN_OPCODE; ++ ctxt.force_update = 1; ++ if (count == i || !atomic) { ++ rval = apc_cache_insert_mult(apc_cache, keys, cache_entries, &ctxt, t, i TSRMLS_CC); ++ atomic_fail = 0; ++ } else { ++ atomic_fail = 1; ++ } + -+PHP_INI_BEGIN() -+STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.shm_size", "30", PHP_INI_SYSTEM, OnUpdateInt, shm_size, zend_apc_globals, apc_globals) -+STD_PHP_INI_BOOLEAN("apc.include_once_override", "0", PHP_INI_SYSTEM, OnUpdateBool, include_once, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.num_files_hint", "1000", PHP_INI_SYSTEM, OnUpdateInt, num_files_hint, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.user_entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateInt, user_entries_hint, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateInt, gc_ttl, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, ttl, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.user_ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, user_ttl, zend_apc_globals, apc_globals) -+#if APC_MMAP -+STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apc_globals, apc_globals) -+#endif -+PHP_INI_ENTRY("apc.filters", NULL, PHP_INI_SYSTEM, OnUpdate_filters) -+STD_PHP_INI_BOOLEAN("apc.cache_by_default", "1", PHP_INI_ALL, OnUpdateBool, cache_by_default, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.slam_defense", "0", PHP_INI_SYSTEM, OnUpdateInt, slam_defense, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.file_update_protection", "2", PHP_INI_SYSTEM, OnUpdateInt,file_update_protection, zend_apc_globals, apc_globals) -+STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.max_file_size", "1M", PHP_INI_SYSTEM, OnUpdateInt, max_file_size, zend_apc_globals, apc_globals) -+STD_PHP_INI_BOOLEAN("apc.stat", "1", PHP_INI_SYSTEM, OnUpdateBool, fpstat, zend_apc_globals, apc_globals) -+STD_PHP_INI_BOOLEAN("apc.stat_ctime", "0", PHP_INI_SYSTEM, OnUpdateBool, stat_ctime, zend_apc_globals, apc_globals) -+STD_PHP_INI_BOOLEAN("apc.write_lock", "1", PHP_INI_SYSTEM, OnUpdateBool, write_lock, zend_apc_globals, apc_globals) -+STD_PHP_INI_BOOLEAN("apc.report_autofilter", "0", PHP_INI_SYSTEM, OnUpdateBool, report_autofilter,zend_apc_globals, apc_globals) -+#ifdef MULTIPART_EVENT_FORMDATA -+STD_PHP_INI_BOOLEAN("apc.rfc1867", "0", PHP_INI_SYSTEM, OnUpdateBool, rfc1867, zend_apc_globals, apc_globals) -+#endif -+STD_PHP_INI_BOOLEAN("apc.localcache", "0", PHP_INI_SYSTEM, OnUpdateBool, localcache, zend_apc_globals, apc_globals) -+STD_PHP_INI_ENTRY("apc.localcache.size", "512", PHP_INI_SYSTEM, OnUpdateInt, localcache_size, zend_apc_globals, apc_globals) -+PHP_INI_END() ++ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(file), &hpos); ++ for(c=0; c < i; c++) { ++ zend_hash_get_current_data_ex(Z_ARRVAL_P(file), (void**)&hentry, &hpos); ++ if (rval && rval[c] != 1) { ++ add_assoc_long(return_value, Z_STRVAL_PP(hentry), -2); /* -2: input or cache insertion error */ ++ if (cache_entries[c]) { ++ apc_pool_destroy(cache_entries[c]->pool TSRMLS_CC); ++ } ++ } ++ if (op_arrays[c]) { ++ destroy_op_array(op_arrays[c] TSRMLS_CC); ++ efree(op_arrays[c]); ++ } ++ if (atomic_fail && cache_entries[c]) { ++ apc_pool_destroy(cache_entries[c]->pool TSRMLS_CC); ++ } ++ if (keys[c].type == APC_CACHE_KEY_FPFILE) { ++ efree((void*)keys[c].data.fpfile.fullpath); ++ } else if (keys[c].type == APC_CACHE_KEY_USER) { ++ efree((void*)keys[c].data.user.identifier); ++ } ++ zend_hash_move_forward_ex(Z_ARRVAL_P(file), &hpos); ++ } ++ efree(op_arrays); ++ efree(keys); ++ efree(cache_entries); ++ if (rval) { ++ efree(rval); ++ } + -+/* }}} */ ++ } ++ ++ /* Return class/function tables to previous states, destroy temp tables */ ++ APCG(force_file_update) = 0; ++ CG(function_table) = cg_orig_function_table; ++ zend_hash_destroy(&cg_function_table); ++ CG(class_table) = cg_orig_class_table; ++ zend_hash_destroy(&cg_class_table); ++ EG(function_table) = eg_orig_function_table; ++ EG(class_table) = eg_orig_class_table; ++ ++ /* Restore global settings */ ++ APCG(filters) = filters; ++ APCG(cache_by_default) = cache_by_default; ++ ++ APCG(current_cache) = NULL; ++ HANDLE_UNBLOCK_INTERRUPTIONS(); + -+/* {{{ PHP_MINFO_FUNCTION(apc) */ -+static PHP_MINFO_FUNCTION(apc) -+{ -+ php_info_print_table_start(); -+ php_info_print_table_row(2, "APC Support", APCG(enabled) ? "enabled" : "disabled"); -+ php_info_print_table_row(2, "Version", APC_VERSION); -+#if APC_MMAP -+ php_info_print_table_row(2, "MMAP Support", "Enabled"); -+ php_info_print_table_row(2, "MMAP File Mask", APCG(mmap_file_mask)); -+#else -+ php_info_print_table_row(2, "MMAP Support", "Disabled"); -+#endif -+#if APC_SEM_LOCKS -+ php_info_print_table_row(2, "Locking type", "IPC Semaphore"); -+#elif APC_FUTEX_LOCKS -+ php_info_print_table_row(2, "Locking type", "Linux Futex Locks"); -+#elif APC_PTHREADMUTEX_LOCKS -+ php_info_print_table_row(2, "Locking type", "pthread mutex Locks"); -+#elif APC_SPIN_LOCKS -+ php_info_print_table_row(2, "Locking type", "spin Locks"); -+#else -+ php_info_print_table_row(2, "Locking type", "File Locks"); -+#endif -+ php_info_print_table_row(2, "Revision", "$Revision: 3.140 $"); -+ php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__); -+ php_info_print_table_end(); -+ DISPLAY_INI_ENTRIES(); +} +/* }}} */ + -+#ifdef MULTIPART_EVENT_FORMDATA -+extern int apc_rfc1867_progress(unsigned int event, void *event_data, void **extra TSRMLS_DC); -+#endif ++/* {{{ proto mixed apc_bin_dump([array files [, array user_vars]]) ++ Returns a binary dump of the given files and user variables from the APC cache. ++ A NULL for files or user_vars signals a dump of every entry, while array() will dump nothing. ++ */ ++PHP_FUNCTION(apc_bin_dump) { + -+/* {{{ PHP_MINIT_FUNCTION(apc) */ -+static PHP_MINIT_FUNCTION(apc) -+{ -+ ZEND_INIT_MODULE_GLOBALS(apc, php_apc_init_globals, php_apc_shutdown_globals); ++ zval *z_files = NULL, *z_user_vars = NULL; ++ HashTable *h_files, *h_user_vars; ++ apc_bd_t *bd; + -+ REGISTER_INI_ENTRIES(); ++ if(!APCG(enabled)) { ++ apc_warning("APC is not enabled, apc_bin_dump not available." TSRMLS_CC); ++ RETURN_FALSE; ++ } + -+ /* Disable APC in cli mode unless overridden by apc.enable_cli */ -+ if(!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) { -+ APCG(enabled) = 0; ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!a!", &z_files, &z_user_vars) == FAILURE) { ++ return; + } + -+ if (APCG(enabled)) { -+ if(APCG(initialized)) { -+ apc_process_init(module_number TSRMLS_CC); -+ } else { -+ apc_module_init(module_number TSRMLS_CC); -+ apc_zend_init(TSRMLS_C); -+ apc_process_init(module_number TSRMLS_CC); -+#ifdef MULTIPART_EVENT_FORMDATA -+ /* File upload progress tracking */ -+ if(APCG(rfc1867)) { -+ php_rfc1867_callback = apc_rfc1867_progress; -+ } -+#endif -+ } ++ h_files = z_files ? Z_ARRVAL_P(z_files) : NULL; ++ h_user_vars = z_user_vars ? Z_ARRVAL_P(z_user_vars) : NULL; ++ bd = apc_bin_dump(h_files, h_user_vars TSRMLS_CC); ++ if(bd) { ++ RETVAL_STRINGL((char*)bd, bd->size-1, 0); ++ } else { ++ apc_error("Unknown error encountered during apc_bin_dump." TSRMLS_CC); ++ RETVAL_NULL(); + } + -+ return SUCCESS; ++ return; +} -+/* }}} */ + -+/* {{{ PHP_MSHUTDOWN_FUNCTION(apc) */ -+static PHP_MSHUTDOWN_FUNCTION(apc) -+{ -+ if(APCG(enabled)) { -+ apc_process_shutdown(TSRMLS_C); -+ apc_zend_shutdown(TSRMLS_C); -+ apc_module_shutdown(TSRMLS_C); -+#ifndef ZTS -+ php_apc_shutdown_globals(&apc_globals); -+#endif ++/* {{{ proto mixed apc_bin_dumpfile(array files, array user_vars, string filename, [int flags [, resource context]]) ++ Output a binary dump of the given files and user variables from the APC cache to the named file. ++ */ ++PHP_FUNCTION(apc_bin_dumpfile) { ++ ++ zval *z_files = NULL, *z_user_vars = NULL; ++ HashTable *h_files, *h_user_vars; ++ char *filename = NULL; ++ int filename_len; ++ long flags=0; ++ zval *zcontext = NULL; ++ php_stream_context *context = NULL; ++ php_stream *stream; ++ int numbytes = 0; ++ apc_bd_t *bd; ++ ++ if(!APCG(enabled)) { ++ apc_warning("APC is not enabled, apc_bin_dumpfile not available." TSRMLS_CC); ++ RETURN_FALSE; + } -+#ifdef ZTS -+ ts_free_id(apc_globals_id); -+#endif -+ UNREGISTER_INI_ENTRIES(); -+ return SUCCESS; -+} -+/* }}} */ + -+/* {{{ PHP_RINIT_FUNCTION(apc) */ -+static PHP_RINIT_FUNCTION(apc) -+{ -+ if(APCG(enabled)) { -+ apc_request_init(TSRMLS_C); ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!s|lr!", &z_files, &z_user_vars, &filename, &filename_len, &flags, &zcontext) == FAILURE) { ++ return; + } -+ return SUCCESS; -+} -+/* }}} */ + -+/* {{{ PHP_RSHUTDOWN_FUNCTION(apc) */ -+static PHP_RSHUTDOWN_FUNCTION(apc) -+{ -+ if(APCG(enabled)) { -+ apc_request_shutdown(TSRMLS_C); ++ if(!filename_len) { ++ apc_error("apc_bin_dumpfile filename argument must be a valid filename." TSRMLS_CC); ++ RETURN_FALSE; + } -+ return SUCCESS; -+} -+/* }}} */ + -+/* {{{ proto array apc_cache_info([string type] [, bool limited]) */ -+PHP_FUNCTION(apc_cache_info) -+{ -+ apc_cache_info_t* info; -+ apc_cache_link_t* p; -+ zval* list; -+ char *cache_type; -+ int ct_len; -+ zend_bool limited=0; ++ h_files = z_files ? Z_ARRVAL_P(z_files) : NULL; ++ h_user_vars = z_user_vars ? Z_ARRVAL_P(z_user_vars) : NULL; ++ bd = apc_bin_dump(h_files, h_user_vars TSRMLS_CC); ++ if(!bd) { ++ apc_error("Unknown error encountered during apc_bin_dumpfile." TSRMLS_CC); ++ RETURN_FALSE; ++ } ++ ++ ++ /* Most of the following has been taken from the file_get/put_contents functions */ ++ ++ context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); ++ stream = php_stream_open_wrapper_ex(filename, (flags & PHP_FILE_APPEND) ? "ab" : "wb", ++ ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context); ++ if (stream == NULL) { ++ efree(bd); ++ apc_error("Unable to write to file in apc_bin_dumpfile." TSRMLS_CC); ++ RETURN_FALSE; ++ } ++ ++ if (flags & LOCK_EX && php_stream_lock(stream, LOCK_EX)) { ++ php_stream_close(stream); ++ efree(bd); ++ apc_error("Unable to get a lock on file in apc_bin_dumpfile." TSRMLS_CC); ++ RETURN_FALSE; ++ } + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &cache_type, &ct_len, &limited) == FAILURE) { -+ return; ++ numbytes = php_stream_write(stream, (char*)bd, bd->size); ++ if(numbytes != bd->size) { ++ numbytes = -1; + } + -+ if(ZEND_NUM_ARGS()) { -+ if(!strcasecmp(cache_type,"user")) { -+ info = apc_cache_info(apc_user_cache, limited); -+ } else { -+ info = apc_cache_info(apc_cache, limited); -+ } -+ } else info = apc_cache_info(apc_cache, limited); ++ php_stream_close(stream); ++ efree(bd); + -+ if(!info) { -+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file"); ++ if(numbytes < 0) { ++ apc_error("Only %d of %d bytes written, possibly out of free disk space" TSRMLS_CC, numbytes, bd->size); + RETURN_FALSE; + } + -+ array_init(return_value); -+ add_assoc_long(return_value, "num_slots", info->num_slots); -+ add_assoc_long(return_value, "ttl", info->ttl); -+ add_assoc_long(return_value, "num_hits", info->num_hits); -+ add_assoc_long(return_value, "num_misses", info->num_misses); -+ add_assoc_long(return_value, "start_time", info->start_time); -+ add_assoc_long(return_value, "expunges", info->expunges); -+ add_assoc_long(return_value, "mem_size", info->mem_size); -+ add_assoc_long(return_value, "num_entries", info->num_entries); -+ add_assoc_long(return_value, "num_inserts", info->num_inserts); -+#ifdef MULTIPART_EVENT_FORMDATA -+ add_assoc_long(return_value, "file_upload_progress", 1); -+#else -+ add_assoc_long(return_value, "file_upload_progress", 0); -+#endif -+#if APC_MMAP -+ add_assoc_stringl(return_value, "memory_type", "mmap", sizeof("mmap")-1, 1); -+#else -+ add_assoc_stringl(return_value, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1); -+#endif -+#if APC_SEM_LOCKS -+ add_assoc_stringl(return_value, "locking_type", "IPC semaphore", sizeof("IPC semaphore")-1, 1); -+#elif APC_FUTEX_LOCKS -+ add_assoc_stringl(return_value, "locking_type", "Linux Futex", sizeof("Linux Futex")-1, 1); -+#elif APC_PTHREADMUTEX_LOCKS -+ add_assoc_stringl(return_value, "locking_type", "pthread mutex", sizeof("pthread mutex")-1, 1); -+#elif APC_SPIN_LOCKS -+ add_assoc_stringl(return_value, "locking_type", "spin", sizeof("spin")-1, 1); -+#else -+ add_assoc_stringl(return_value, "locking_type", "file", sizeof("file")-1, 1); -+#endif -+ if(limited) { -+ apc_cache_free_info(info); -+ return; ++ RETURN_LONG(numbytes); ++} ++ ++/* {{{ proto mixed apc_bin_load(string data, [int flags]) ++ Load the given binary dump into the APC file/user cache. ++ */ ++PHP_FUNCTION(apc_bin_load) { ++ ++ int data_len; ++ char *data; ++ long flags = 0; ++ ++ if(!APCG(enabled)) { ++ apc_warning("APC is not enabled, apc_bin_load not available." TSRMLS_CC); ++ RETURN_FALSE; + } -+ -+ ALLOC_INIT_ZVAL(list); -+ array_init(list); -+ -+ for (p = info->list; p != NULL; p = p->next) { -+ zval* link; -+ -+ ALLOC_INIT_ZVAL(link); -+ array_init(link); -+ -+ if(p->type == APC_CACHE_ENTRY_FILE) { -+ add_assoc_string(link, "filename", p->data.file.filename, 1); -+ add_assoc_long(link, "device", p->data.file.device); -+ add_assoc_long(link, "inode", p->data.file.inode); -+ add_assoc_string(link, "type", "file", 1); -+ } else if(p->type == APC_CACHE_ENTRY_USER) { -+ add_assoc_string(link, "info", p->data.user.info, 1); -+ add_assoc_long(link, "ttl", (long)p->data.user.ttl); -+ add_assoc_string(link, "type", "user", 1); -+ } -+ add_assoc_long(link, "num_hits", p->num_hits); -+ add_assoc_long(link, "mtime", p->mtime); -+ add_assoc_long(link, "creation_time", p->creation_time); -+ add_assoc_long(link, "deletion_time", p->deletion_time); -+ add_assoc_long(link, "access_time", p->access_time); -+ add_assoc_long(link, "ref_count", p->ref_count); -+ add_assoc_long(link, "mem_size", p->mem_size); -+ add_next_index_zval(list, link); -+ } -+ add_assoc_zval(return_value, "cache_list", list); -+ -+ ALLOC_INIT_ZVAL(list); -+ array_init(list); -+ -+ for (p = info->deleted_list; p != NULL; p = p->next) { -+ zval* link; -+ -+ ALLOC_INIT_ZVAL(link); -+ array_init(link); -+ -+ if(p->type == APC_CACHE_ENTRY_FILE) { -+ add_assoc_string(link, "filename", p->data.file.filename, 1); -+ add_assoc_long(link, "device", p->data.file.device); -+ add_assoc_long(link, "inode", p->data.file.inode); -+ add_assoc_string(link, "type", "file", 1); -+ } else if(p->type == APC_CACHE_ENTRY_USER) { -+ add_assoc_string(link, "info", p->data.user.info, 1); -+ add_assoc_long(link, "ttl", (long)p->data.user.ttl); -+ add_assoc_string(link, "type", "user", 1); -+ } -+ add_assoc_long(link, "num_hits", p->num_hits); -+ add_assoc_long(link, "mtime", p->mtime); -+ add_assoc_long(link, "creation_time", p->creation_time); -+ add_assoc_long(link, "deletion_time", p->deletion_time); -+ add_assoc_long(link, "access_time", p->access_time); -+ add_assoc_long(link, "ref_count", p->ref_count); -+ add_assoc_long(link, "mem_size", p->mem_size); -+ add_next_index_zval(list, link); -+ } -+ add_assoc_zval(return_value, "deleted_list", list); -+ -+ apc_cache_free_info(info); -+} -+/* }}} */ -+ -+/* {{{ proto void apc_clear_cache() */ -+PHP_FUNCTION(apc_clear_cache) -+{ -+ char *cache_type; -+ int ct_len; + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache_type, &ct_len) == FAILURE) { ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &flags) == FAILURE) { + return; + } + -+ if(ZEND_NUM_ARGS()) { -+ if(!strcasecmp(cache_type,"user")) { -+ apc_cache_clear(apc_user_cache); -+ RETURN_TRUE; -+ } ++ if(!data_len || data_len != ((apc_bd_t*)data)->size -1) { ++ apc_error("apc_bin_load string argument does not appear to be a valid APC binary dump due to size (%d vs expected %d)." TSRMLS_CC, data_len, ((apc_bd_t*)data)->size -1); ++ RETURN_FALSE; + } -+ apc_cache_clear(apc_cache); -+} -+/* }}} */ + -+/* {{{ proto array apc_sma_info([bool limited]) */ -+PHP_FUNCTION(apc_sma_info) -+{ -+ apc_sma_info_t* info; -+ zval* block_lists; -+ int i; -+ zend_bool limited = 0; ++ apc_bin_load((apc_bd_t*)data, (int)flags TSRMLS_CC); + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &limited) == FAILURE) { -+ return; -+ } ++ RETURN_TRUE; ++} + -+ info = apc_sma_info(limited); ++/* {{{ proto mixed apc_bin_loadfile(string filename, [resource context, [int flags]]) ++ Load the given binary dump from the named file into the APC file/user cache. ++ */ ++PHP_FUNCTION(apc_bin_loadfile) { + -+ if(!info) { -+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC SMA info available. Perhaps APC is disabled via apc.enabled?"); ++ char *filename; ++ int filename_len; ++ zval *zcontext = NULL; ++ long flags; ++ php_stream_context *context = NULL; ++ php_stream *stream; ++ char *data; ++ int len; ++ ++ if(!APCG(enabled)) { ++ apc_warning("APC is not enabled, apc_bin_loadfile not available." TSRMLS_CC); + RETURN_FALSE; + } + -+ array_init(return_value); -+ add_assoc_long(return_value, "num_seg", info->num_seg); -+ add_assoc_long(return_value, "seg_size", info->seg_size); -+ add_assoc_long(return_value, "avail_mem", apc_sma_get_avail_mem()); -+ -+ if(limited) { -+ apc_sma_free_info(info); ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r!l", &filename, &filename_len, &zcontext, &flags) == FAILURE) { + return; + } + -+#if ALLOC_DISTRIBUTION -+ { -+ size_t *adist = apc_sma_get_alloc_distribution(); -+ zval* list; -+ ALLOC_INIT_ZVAL(list); -+ array_init(list); -+ for(i=0; i<30; i++) { -+ add_next_index_long(list, adist[i]); -+ } -+ add_assoc_zval(return_value, "adist", list); ++ if(!filename_len) { ++ apc_error("apc_bin_loadfile filename argument must be a valid filename." TSRMLS_CC); ++ RETURN_FALSE; + } -+#endif -+ ALLOC_INIT_ZVAL(block_lists); -+ array_init(block_lists); -+ -+ for (i = 0; i < info->num_seg; i++) { -+ apc_sma_link_t* p; -+ zval* list; + -+ ALLOC_INIT_ZVAL(list); -+ array_init(list); ++ context = php_stream_context_from_zval(zcontext, 0); ++ stream = php_stream_open_wrapper_ex(filename, "rb", ++ ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context); ++ if (!stream) { ++ apc_error("Unable to read from file in apc_bin_loadfile." TSRMLS_CC); ++ RETURN_FALSE; ++ } + -+ for (p = info->list[i]; p != NULL; p = p->next) { -+ zval* link; ++ len = php_stream_copy_to_mem(stream, &data, PHP_STREAM_COPY_ALL, 0); ++ if(len == 0) { ++ apc_warning("File passed to apc_bin_loadfile was empty: %s." TSRMLS_CC, filename); ++ RETURN_FALSE; ++ } else if(len < 0) { ++ apc_warning("Error reading file passed to apc_bin_loadfile: %s." TSRMLS_CC, filename); ++ RETURN_FALSE; ++ } else if(len != ((apc_bd_t*)data)->size) { ++ apc_warning("file passed to apc_bin_loadfile does not appear to be valid due to size (%d vs expected %d)." TSRMLS_CC, len, ((apc_bd_t*)data)->size -1); ++ RETURN_FALSE; ++ } ++ php_stream_close(stream); + -+ ALLOC_INIT_ZVAL(link); -+ array_init(link); ++ apc_bin_load((apc_bd_t*)data, (int)flags TSRMLS_CC); ++ efree(data); + -+ add_assoc_long(link, "size", p->size); -+ add_assoc_long(link, "offset", p->offset); -+ add_next_index_zval(list, link); -+ } -+ add_next_index_zval(block_lists, list); -+ } -+ add_assoc_zval(return_value, "block_lists", block_lists); -+ apc_sma_free_info(info); ++ RETURN_TRUE; +} +/* }}} */ + -+/* {{{ _apc_store */ -+int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC) { -+ apc_cache_entry_t *entry; -+ apc_cache_key_t key; -+ time_t t; -+ size_t mem_size = 0; -+ -+#if PHP_API_VERSION <= 20041225 -+#if HAVE_APACHE && defined(APC_PHP4_STAT) -+ t = ((request_rec *)SG(server_context))->request_time; ++/* {{{ arginfo */ ++#if (PHP_MAJOR_VERSION >= 6 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3)) ++# define PHP_APC_ARGINFO +#else -+ t = time(0); ++# define PHP_APC_ARGINFO static +#endif -+#else -+ t = sapi_get_request_time(TSRMLS_C); ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_store, 0, 0, 2) ++ ZEND_ARG_INFO(0, key) ++ ZEND_ARG_INFO(0, var) ++ ZEND_ARG_INFO(0, ttl) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_clear_cache, 0, 0, 0) ++ ZEND_ARG_INFO(0, info) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_sma_info, 0, 0, 0) ++ ZEND_ARG_INFO(0, limited) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_cache_info, 0, 0, 0) ++ ZEND_ARG_INFO(0, type) ++ ZEND_ARG_INFO(0, limited) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_define_constants, 0, 0, 2) ++ ZEND_ARG_INFO(0, key) ++ ZEND_ARG_INFO(0, constants) ++ ZEND_ARG_INFO(0, case_sensitive) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO(arginfo_apc_delete_file, 0) ++ ZEND_ARG_INFO(0, keys) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO(arginfo_apc_delete, 0) ++ ZEND_ARG_INFO(0, keys) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_fetch, 0, 0, 1) ++ ZEND_ARG_INFO(0, key) ++ ZEND_ARG_INFO(1, success) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_inc, 0, 0, 1) ++ ZEND_ARG_INFO(0, key) ++ ZEND_ARG_INFO(0, step) ++ ZEND_ARG_INFO(1, success) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO(arginfo_apc_cas, 0) ++ ZEND_ARG_INFO(0, key) ++ ZEND_ARG_INFO(0, old) ++ ZEND_ARG_INFO(0, new) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_load_constants, 0, 0, 1) ++ ZEND_ARG_INFO(0, key) ++ ZEND_ARG_INFO(0, case_sensitive) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_compile_file, 0, 0, 1) ++ ZEND_ARG_INFO(0, filenames) ++ ZEND_ARG_INFO(0, atomic) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_bin_dump, 0, 0, 0) ++ ZEND_ARG_INFO(0, files) ++ ZEND_ARG_INFO(0, user_vars) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_bin_dumpfile, 0, 0, 3) ++ ZEND_ARG_INFO(0, files) ++ ZEND_ARG_INFO(0, user_vars) ++ ZEND_ARG_INFO(0, filename) ++ ZEND_ARG_INFO(0, flags) ++ ZEND_ARG_INFO(0, context) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_bin_load, 0, 0, 1) ++ ZEND_ARG_INFO(0, data) ++ ZEND_ARG_INFO(0, flags) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO_EX(arginfo_apc_bin_loadfile, 0, 0, 1) ++ ZEND_ARG_INFO(0, filename) ++ ZEND_ARG_INFO(0, context) ++ ZEND_ARG_INFO(0, flags) ++ZEND_END_ARG_INFO() ++ ++PHP_APC_ARGINFO ++ZEND_BEGIN_ARG_INFO(arginfo_apc_exists, 0) ++ ZEND_ARG_INFO(0, keys) ++ZEND_END_ARG_INFO() ++/* }}} */ ++ ++/* {{{ apc_functions[] */ ++zend_function_entry apc_functions[] = { ++ PHP_FE(apc_cache_info, arginfo_apc_cache_info) ++ PHP_FE(apc_clear_cache, arginfo_apc_clear_cache) ++ PHP_FE(apc_sma_info, arginfo_apc_sma_info) ++ PHP_FE(apc_store, arginfo_apc_store) ++ PHP_FE(apc_fetch, arginfo_apc_fetch) ++ PHP_FE(apc_delete, arginfo_apc_delete) ++ PHP_FE(apc_delete_file, arginfo_apc_delete_file) ++ PHP_FE(apc_define_constants, arginfo_apc_define_constants) ++ PHP_FE(apc_load_constants, arginfo_apc_load_constants) ++ PHP_FE(apc_compile_file, arginfo_apc_compile_file) ++ PHP_FE(apc_add, arginfo_apc_store) ++ PHP_FE(apc_inc, arginfo_apc_inc) ++ PHP_FE(apc_dec, arginfo_apc_inc) ++ PHP_FE(apc_cas, arginfo_apc_cas) ++ PHP_FE(apc_bin_dump, arginfo_apc_bin_dump) ++ PHP_FE(apc_bin_load, arginfo_apc_bin_load) ++ PHP_FE(apc_bin_dumpfile, arginfo_apc_bin_dumpfile) ++ PHP_FE(apc_bin_loadfile, arginfo_apc_bin_loadfile) ++ PHP_FE(apc_exists, arginfo_apc_exists) ++ {NULL, NULL, NULL} ++}; ++/* }}} */ ++ ++/* {{{ module definition structure */ ++ ++zend_module_entry apc_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "apc", ++ apc_functions, ++ PHP_MINIT(apc), ++ PHP_MSHUTDOWN(apc), ++ PHP_RINIT(apc), ++ PHP_RSHUTDOWN(apc), ++ PHP_MINFO(apc), ++ PHP_APC_VERSION, ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++#ifdef COMPILE_DL_APC ++ZEND_GET_MODULE(apc) +#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 ++ */ +diff -Naur a/ext/apc/php_apc.h b/ext/apc/php_apc.h +--- a/ext/apc/php_apc.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/php_apc.h 2012-07-20 00:10:35.000000000 +0200 +@@ -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 | ++ | George Schlossnagle | ++ | Rasmus Lerdorf | ++ +----------------------------------------------------------------------+ ++ ++ This software was contributed to PHP by Community Connect Inc. in 2002 ++ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. ++ Future revisions and derivatives of this source code must acknowledge ++ Community Connect Inc. as the original contributor of this module by ++ leaving this note intact in the source code. ++ ++ All other licensing and usage conditions are those of the PHP Group. ++ ++ */ ++ ++/* $Id: php_apc.h 326713 2012-07-19 22:07:31Z rasmus $ */ ++ ++#ifndef PHP_APC_H ++#define PHP_APC_H ++ ++#include "apc_php.h" ++#include "apc_globals.h" ++ ++#define PHP_APC_VERSION "3.1.11" ++ ++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 ++ */ +diff -Naur a/ext/apc/TECHNOTES.txt b/ext/apc/TECHNOTES.txt +--- a/ext/apc/TECHNOTES.txt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/TECHNOTES.txt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,361 @@ ++APC Quick-Start Braindump ++ ++This is a rapidly written braindump of how APC currently works in the ++form of a quick-start guide to start hacking on APC. ++ ++1. Install and use APC a bit so you know what it does from the end-user's ++ perspective. ++ user-space functions are all explained here: ++ ++2. Grab the current APC code from CVS: ++ ++ cvs -d:pserver:cvsread@cvs.php.net:/repository login ++ Password: phpfi ++ cvs -d:pserver:cvsread@cvs.php.net:/repository co pecl/apc ++ ++ apc/php_apc.c has most of the code for the user-visible stuff. It is ++ also a regular PHP extension in the sense that there are MINIT, MINFO, ++ MSHUTDOWN, RSHUTDOWN, etc. functions. ++ ++3. Build it. ++ ++ cd pecl/apc ++ phpize ++ ./configure --enable-apc --enable-mmap ++ make ++ cp modules/apc.so /usr/local/lib/php ++ apachectl restart ++ ++4. Debugging Hints ++ ++ apachectl stop ++ gdb /usr/bin/httpd ++ break ?? ++ run -X ++ ++ Grab the .gdbinit from the PHP source tree and have a look at the macros. ++ ++5. Look through apc/apc_sma.c ++ It is a pretty standard memory allocator. ++ ++ apc_sma_malloc, apc_sma_realloc, apc_sma_strdup and apc_sma_free behave to the ++ caller just like malloc, realloc, strdup and free ++ ++ On server startup the MINIT hook in php_apc.c calls apc_module_init() in ++ apc_main.c which in turn calls apc_sma_init(). apc_sma_init calls into ++ apc_mmap.c to mmap the specified sized segment (I tend to just use a single ++ segment). apc_mmap.c should be self-explanatory. It mmaps a temp file and ++ then unlinks that file right after the mmap to provide automatic shared memory ++ cleanup in case the process dies. ++ ++ Once the region has been initialized we stick a header_t at the beginning ++ of the region. It contains the total size in header->segsize and the number ++ of bytes available in header->avail. ++ ++ After the header comes a bit of a hack. A zero-sized block is inserted just ++ to make things easier later on. And then a huge block that is basically ++ the size of the entire segment minus the two (for the 0-sized block, and this one) ++ block headers. ++ ++ The code for this is: ++ ++ header = (header_t*) shmaddr; ++ header->segsize = sma_segsize; ++ header->avail = sma_segsize - sizeof(header_t) - sizeof(block_t) - alignword(sizeof(int)); ++ memset(&header->lock,0,sizeof(header->lock)); ++ sma_lock = &header->lock; ++ block = BLOCKAT(sizeof(header_t)); ++ block->size = 0; ++ block->next = sizeof(header_t) + sizeof(block_t); ++ block = BLOCKAT(block->next); ++ block->size = header->avail; ++ block->next = 0; ++ ++ So the shared memory looks like this: ++ ++ +--------+-------+---------------------------------+ ++ | header | block | block | ++ +--------+-------+---------------------------------+ + -+ if(!APCG(enabled)) return 0; ++ sma_shmaddrs[0] gives you the address of header + -+ HANDLE_BLOCK_INTERRUPTIONS(); ++ The blocks are just a simple offset-based linked list (so no pointers): + -+ APCG(mem_size_ptr) = &mem_size; -+ if (!(entry = apc_cache_make_user_entry(strkey, strkey_len + 1, val, ttl))) { -+ APCG(mem_size_ptr) = NULL; -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return 0; -+ } ++ typedef struct block_t block_t; ++ struct block_t { ++ size_t size; /* size of this block */ ++ size_t next; /* offset in segment of next free block */ ++ size_t canary; /* canary to check for memory overwrites */ ++#ifdef __APC_SMA_DEBUG__ ++ int id; /* identifier for the memory block */ ++#endif ++ }; + -+ if (!apc_cache_make_user_key(&key, strkey, strkey_len + 1, t)) { -+ APCG(mem_size_ptr) = NULL; -+ apc_cache_free_entry(entry); -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return 0; -+ } ++ The BLOCKAT macro turns an offset into an actual address for you: + -+ if (!apc_cache_user_insert(apc_user_cache, key, entry, t, exclusive TSRMLS_CC)) { -+ APCG(mem_size_ptr) = NULL; -+ apc_cache_free_entry(entry); -+ apc_cache_expunge(apc_cache,t); -+ apc_cache_expunge(apc_user_cache,t); -+ HANDLE_UNBLOCK_INTERRUPTIONS(); -+ return 0; -+ } ++ #define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset)) + -+ APCG(mem_size_ptr) = NULL; ++ where shmaddr = sma_shaddrs[0] + -+ HANDLE_UNBLOCK_INTERRUPTIONS(); ++ And the OFFSET macro goes the other way: + -+ return 1; -+} -+/* }}} */ ++ #define OFFSET(block) ((int)(((char*)block) - (char*)shmaddr)) + -+/* {{{ proto int apc_store(string key, zval var [, ttl ]) -+ */ -+PHP_FUNCTION(apc_store) { -+ zval *val; -+ char *strkey; -+ int strkey_len; -+ long ttl = 0L; ++ Allocating a block with a call to apc_sma_allocate() walks through the ++ linked list of blocks until it finds one that is >= to the requested size. ++ The first call to apc_sma_allocate() will hit the second block. We then ++ chop up that block so it looks like this: + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) { -+ return; -+ } ++ +--------+-------+-------+-------------------------+ ++ | header | block | block | block | ++ +--------+-------+-------+-------------------------+ + -+ if(!strkey_len) RETURN_FALSE; ++ Then we unlink that block from the linked list so it won't show up ++ as an available block on the next allocate. So we actually have: + -+ if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 0 TSRMLS_CC)) RETURN_TRUE; -+ RETURN_FALSE; -+} -+/* }}} */ ++ +--------+-------+ +-------------------------+ ++ | header | block |------>| block | ++ +--------+-------+ +-------------------------+ + -+/* {{{ proto int apc_add(string key, zval var [, ttl ]) -+ */ -+PHP_FUNCTION(apc_add) { -+ zval *val; -+ char *strkey; -+ int strkey_len; -+ long ttl = 0L; ++ And header->avail along with block->size of the remaining large ++ block are updated accordingly. The arrow there representing the ++ link which now points to a block with an offset further along in ++ the segment. + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) { -+ return; -+ } ++ When the block is freed using apc_sma_deallocate() the steps are ++ basically just reversed. The block is put back and then the deallocate ++ code looks at the block before and after to see if the block immediately ++ before and after are free and if so the blocks are combined. So you never ++ have 2 free blocks next to each other, apart from at the front with that ++ 0-sized dummy block. This mostly prevents fragmentation. I have been ++ toying with the idea of always allocating block at 2^n boundaries to make ++ it more likely that they will be re-used to cut down on fragmentation further. ++ That's what the POWER_OF_TWO_BLOCKSIZE you see in apc_sma.c is all about. ++ ++ Of course, anytime we fiddle with our shared memory segment we lock using ++ the locking macros, LOCK() and UNLOCK(). + -+ if(!strkey_len) RETURN_FALSE; ++ That should mostly take care of the low-level shared memory handling. + -+ if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 1 TSRMLS_CC)) RETURN_TRUE; -+ RETURN_FALSE; -+} -+/* }}} */ ++6. Next up is apc_main.c and apc_cache.c which implement the meat of the ++ cache logic. + -+void *apc_erealloc_wrapper(void *ptr, size_t size) { -+ return _erealloc(ptr, size, 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); -+} ++ The apc_main.c file mostly calls functions in apc_sma.c to allocate memory ++ and apc_cache.c for actual cache manipulation. ++ ++ After the shared memory segment is created and the caches are initialized, ++ apc_module_init() installs the my_compile_file() function overriding Zend's ++ version. I'll talk about my_compile_file() and the rest of apc_compile.c ++ in the next section. For now I will stick with apc_main.c and apc_cache.c ++ and talk about the actual caches. A cache consists of a block of shared ++ memory returned by apc_sma_allocate() via apc_sma_malloc(). You will ++ notice references to apc_emalloc(). apc_emalloc() is just a thin wrapper ++ around PHP's own emalloc() function which allocates per-process memory from ++ PHP's pool-based memory allocator. Don't confuse apc_emalloc() and ++ apc_sma_malloc() as the first is per-process and the second is shared memory. + -+/* {{{ RETURN_ZVAL for php4 */ -+#if !defined(ZEND_ENGINE_2) && !defined(RETURN_ZVAL) -+#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; } -+#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor) -+#define ZVAL_ZVAL(z, zv, copy, dtor) { \ -+ int is_ref, refcount; \ -+ is_ref = (z)->is_ref; \ -+ refcount = (z)->refcount; \ -+ *(z) = *(zv); \ -+ if (copy) { \ -+ zval_copy_ctor(z); \ -+ } \ -+ if (dtor) { \ -+ if (!copy) { \ -+ ZVAL_NULL(zv); \ -+ } \ -+ zval_ptr_dtor(&zv); \ -+ } \ -+ (z)->is_ref = is_ref; \ -+ (z)->refcount = refcount; \ -+ } -+#endif -+/* }}} */ ++ The cache is stored in/described by this struct allocated locally using ++ emalloc(): + -+/* {{{ proto mixed apc_fetch(mixed key) -+ */ -+PHP_FUNCTION(apc_fetch) { -+ zval *key; -+ HashTable *hash; -+ HashPosition hpos; -+ zval **hentry; -+ zval *result; -+ zval *result_entry; -+ char *strkey; -+ int strkey_len; -+ apc_cache_entry_t* entry; -+ time_t t; ++ struct apc_cache_t { ++ void* shmaddr; /* process (local) address of shared cache */ ++ header_t* header; /* cache header (stored in SHM) */ ++ slot_t** slots; /* array of cache slots (stored in SHM) */ ++ int num_slots; /* number of slots in cache */ ++ int gc_ttl; /* maximum time on GC list for a slot */ ++ int ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */ ++ }; + -+ if(!APCG(enabled)) RETURN_FALSE; ++ Whenever you see functions that take a 'cache' argument, this is what they ++ take. And apc_cache_create() returns a pointer to this populated struct. + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) { -+ return; -+ } ++ At the beginning of the cache we have a header. Remember, we are down a level now ++ from the sma stuff. The sma stuff is the low-level shared-memory allocator which ++ has its own header which is completely separate and invisible to apc_cache.c. ++ As far as apc_cache.c is concerned the block of memory it is working with could ++ have come from a call to malloc(). + -+#if PHP_API_VERSION <= 20041225 -+#if HAVE_APACHE && defined(APC_PHP4_STAT) -+ t = ((request_rec *)SG(server_context))->request_time; -+#else -+ t = time(0); -+#endif -+#else -+ t = sapi_get_request_time(TSRMLS_C); -+#endif ++ The header looks like this: + -+ if(Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) { -+ convert_to_string(key); -+ } -+ -+ if(Z_TYPE_P(key) == IS_STRING) { -+ strkey = Z_STRVAL_P(key); -+ strkey_len = Z_STRLEN_P(key); -+ if(!strkey_len) RETURN_FALSE; -+ entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t); -+ if(entry) { -+ /* deep-copy returned shm zval to emalloc'ed return_value */ -+ apc_cache_fetch_zval(return_value, entry->data.user.val, apc_php_malloc, apc_php_free); -+ apc_cache_release(apc_user_cache, entry); -+ } else { -+ RETURN_FALSE; -+ } -+ } else if(Z_TYPE_P(key) == IS_ARRAY) { -+ hash = Z_ARRVAL_P(key); -+ MAKE_STD_ZVAL(result); -+ array_init(result); -+ zend_hash_internal_pointer_reset_ex(hash, &hpos); -+ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { -+ if(Z_TYPE_PP(hentry) != IS_STRING) { -+ apc_wprint("apc_fetch() expects a string or array of strings."); -+ RETURN_FALSE; -+ } -+ entry = apc_cache_user_find(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1, t); -+ if(entry) { -+ /* deep-copy returned shm zval to emalloc'ed return_value */ -+ MAKE_STD_ZVAL(result_entry); -+ apc_cache_fetch_zval(result_entry, entry->data.user.val, apc_php_malloc, apc_php_free); -+ apc_cache_release(apc_user_cache, entry); -+ zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1, &result_entry, sizeof(zval*), NULL); -+ } /* don't set values we didn't find */ -+ zend_hash_move_forward_ex(hash, &hpos); -+ } -+ RETURN_ZVAL(result, 0, 1); -+ } else { -+ apc_wprint("apc_fetch() expects a string or array of strings."); -+ RETURN_FALSE; -+ } ++ typedef struct header_t header_t; ++ struct header_t { ++ int num_hits; /* total successful hits in cache */ ++ int num_misses; /* total unsuccessful hits in cache */ ++ slot_t* deleted_list; /* linked list of to-be-deleted slots */ ++ }; + -+ return; -+} -+/* }}} */ ++ Since this is at the start of the shared memory segment, these values are accessible ++ across all the apache processes and hence access to them has to be locked. + -+/* {{{ proto mixed apc_delete(string key) -+ */ -+PHP_FUNCTION(apc_delete) { -+ char *strkey; -+ int strkey_len; ++ After the header we have an array of slots. The number of slots is user-defined ++ through the apc.num_slots ini hint. Each slot is described by: + -+ if(!APCG(enabled)) RETURN_FALSE; ++ typedef struct slot_t slot_t; ++ struct slot_t { ++ apc_cache_key_t key; /* slot key */ ++ apc_cache_entry_t* value; /* slot value */ ++ slot_t* next; /* next slot in linked list */ ++ int num_hits; /* number of hits to this bucket */ ++ time_t creation_time; /* time slot was initialized */ ++ time_t deletion_time; /* time slot was removed from cache */ ++ time_t access_time; /* time slot was last accessed */ ++ }; + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &strkey, &strkey_len) == FAILURE) { -+ return; -+ } ++ The slot_t *next there is a linked list to other slots that happened to hash to the ++ same array position. + -+ if(!strkey_len) RETURN_FALSE; ++ apc_cache_insert() shows what happens on a new cache insert. + -+ if(apc_cache_user_delete(apc_user_cache, strkey, strkey_len + 1)) { -+ RETURN_TRUE; -+ } else { -+ RETURN_FALSE; -+ } -+} -+/* }}} */ ++ slot = &cache->slots[hash(key) % cache->num_slots]; + -+static void _apc_define_constants(zval *constants, zend_bool case_sensitive TSRMLS_DC) { -+ char *const_key; -+ unsigned int const_key_len; -+ zval **entry; -+ HashPosition pos; ++ cache->slots is our array of slots in the segment. hash() is simply: + -+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(constants), &pos); -+ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(constants), (void**)&entry, &pos) == SUCCESS) { -+ zend_constant c; -+ int key_type; -+ ulong num_key; ++ static unsigned int hash(apc_cache_key_t key) ++ { ++ return key.data.file.device + key.data.file.inode; ++ } + -+ key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(constants), &const_key, &const_key_len, &num_key, 0, &pos); -+ if(key_type != HASH_KEY_IS_STRING) { -+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); -+ continue; -+ } -+ switch(Z_TYPE_PP(entry)) { -+ case IS_LONG: -+ case IS_DOUBLE: -+ case IS_STRING: -+ case IS_BOOL: -+ case IS_RESOURCE: -+ case IS_NULL: -+ break; -+ default: -+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); -+ continue; -+ } -+ c.value = **entry; -+ zval_copy_ctor(&c.value); -+ c.flags = case_sensitive; -+ c.name = zend_strndup(const_key, const_key_len); -+ c.name_len = const_key_len; -+#ifdef ZEND_ENGINE_2 -+ c.module_number = PHP_USER_CONSTANT; -+#endif -+ zend_register_constant(&c TSRMLS_CC); ++ That is, we use the file's device and inode to uniquely identify it. Initially ++ we had used the file's full path, but getting that requires a realpath() call which ++ is amazingly expensive since it has to stat each component of the path to resolve ++ symlinks and get rid of relative path components. By using the device+inode we ++ can uniquely identify a file with a single stat. + -+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); -+ } -+} ++ So, on an insert we find the array position in the slots array by hashing the device+inode. ++ If there are currently no other slots there, we just create the slot and stick it into ++ the array: + -+/* {{{ proto mixed apc_define_constants(string key, array constants [,bool case-sensitive]) -+ */ -+PHP_FUNCTION(apc_define_constants) { -+ char *strkey; -+ int strkey_len; -+ zval *constants = NULL; -+ zend_bool case_sensitive = 1; -+ int argc = ZEND_NUM_ARGS(); ++ *slot = make_slot(key, value, *slot, t) + -+ if (zend_parse_parameters(argc TSRMLS_CC, "sa|b", &strkey, &strkey_len, &constants, &case_sensitive) == FAILURE) { -+ return; -+ } ++ If there are other slots already at this position we walk the link list to get to ++ the end. Here is the loop: + -+ if(!strkey_len) RETURN_FALSE; ++ while (*slot) { ++ 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 ((*slot)->key.mtime != key.mtime) { ++ remove_slot(cache, slot); ++ break; ++ } ++ UNLOCK(cache); ++ return 0; ++ } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { ++ remove_slot(cache, slot); ++ continue; ++ } ++ slot = &(*slot)->next; ++ } + -+ _apc_define_constants(constants, case_sensitive TSRMLS_CC); -+ if(_apc_store(strkey, strkey_len, constants, 0, 0 TSRMLS_CC)) RETURN_TRUE; -+ RETURN_FALSE; -+} /* }}} */ ++ That first key_equals() check sees if we have an exact match meaning the file ++ is already in the cache. Since we try to find the file in the cache before doing ++ an insert, this will generally only happen if another process managed to beat us ++ to inserting it. If we have a newer version of the file at this point we remove ++ it an insert the new version. If our version is not newer we just return without ++ doing anything. + -+/* {{{ proto mixed apc_load_constants(string key [, bool case-sensitive]) -+ */ -+PHP_FUNCTION(apc_load_constants) { -+ char *strkey; -+ int strkey_len; -+ apc_cache_entry_t* entry; -+ time_t t; -+ zend_bool case_sensitive = 1; ++ While walking the linked list we also check to see if the cache has a TTL defined. ++ If while walking the linked list we see a slot that has expired, we remove it ++ since we are right there looking at it. This is the only place we remove stale ++ entries unless the shared memory segment fills up and we force a full expunge via ++ apc_cache_expunge(). apc_cache_expunge() walks the entire slots array and walks ++ down every linked list removing stale slots to free up room. This is obviously ++ slow and thus only happens when we have run out of room. + -+ if(!APCG(enabled)) RETURN_FALSE; -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &strkey, &strkey_len, &case_sensitive) == FAILURE) { -+ return; -+ } ++ apc_cache_find() simply hashes and returns the entry if it is there. If it is there ++ but older than the mtime in the entry we are looking for, we delete the one that is ++ there and return indicating we didn't find it. + -+ if(!strkey_len) RETURN_FALSE; ++ Next we need to understand what an actual cache entry looks like. Have a look at ++ apc_cache.h for the structs. I sort of glossed over the key part earlier saying ++ that we just used the device+inode to find a hash slot. It is actually a bit more ++ complex than that because we have two kinds of caches. We have the standard file ++ cache containing opcode arrays, but we also have a user-controlled cache that the ++ user can insert whatever they want into via apc_store(). For the user cache we ++ obviously don't have a device+inode. The actual identifier is provided by the user ++ as a char *. So the key is actually a union that looks like this: + -+#if PHP_API_VERSION <= 20041225 -+#if HAVE_APACHE && defined(APC_PHP4_STAT) -+ t = ((request_rec *)SG(server_context))->request_time; -+#else -+ t = time(0); -+#endif -+#else -+ t = sapi_get_request_time(TSRMLS_C); -+#endif ++ typedef union _apc_cache_key_data_t { ++ struct { ++ int device; /* the filesystem device */ ++ int inode; /* the filesystem inode */ ++ } file; ++ struct { ++ char *identifier; ++ } user; ++ } apc_cache_key_data_t; + -+ entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t); ++ struct apc_cache_key_t { ++ apc_cache_key_data_t data; ++ int mtime; /* the mtime of this cached entry */ ++ }; + -+ if(entry) { -+ _apc_define_constants(entry->data.user.val, case_sensitive TSRMLS_CC); -+ apc_cache_release(apc_user_cache, entry); -+ RETURN_TRUE; -+ } else { -+ RETURN_FALSE; -+ } -+} -+/* }}} */ ++ And we have two sets of functions to do inserts and finds. apc_cache_user_find() ++ and apc_cache_user_insert() operate on the user cache. + -+/* {{{ proto boolean apc_compile_file(string filename) -+ */ -+PHP_FUNCTION(apc_compile_file) { -+ char *filename; -+ int filename_len; -+ zend_file_handle file_handle; -+ zend_op_array *op_array; -+ long slam_defense = 0; -+ char** filters = NULL; -+ zend_bool cache_by_default = 1; -+ HashTable cg_function_table, cg_class_table, eg_function_table, eg_class_table; -+ HashTable *cg_orig_function_table, *cg_orig_class_table, *eg_orig_function_table, *eg_orig_class_table; ++ Ok, on to the actual cache entry. Again, because we have two kinds of caches, we ++ also have the corresponding two kinds of cache entries described by this union: + -+ if(!APCG(enabled)) RETURN_FALSE; ++ typedef union _apc_cache_entry_value_t { ++ struct { ++ char *filename; /* absolute path to source file */ ++ zend_op_array* op_array; /* op_array allocated in shared memory */ ++ apc_function_t* functions; /* array of apc_function_t's */ ++ apc_class_t* classes; /* array of apc_class_t's */ ++ } file; ++ struct { ++ char *info; ++ zval *val; ++ unsigned int ttl; ++ } user; ++ } apc_cache_entry_value_t; + -+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { -+ return; -+ } ++ And then the actual cache entry: + -+ if(!filename) RETURN_FALSE; ++ struct apc_cache_entry_t { ++ apc_cache_entry_value_t data; ++ unsigned char type; ++ int ref_count; ++ }; + -+ /* If slam defense is active, temporarily disable */ -+ if(APCG(slam_defense)) { -+ slam_defense = APCG(slam_defense); -+ APCG(slam_defense) = 0; -+ } -+ -+ /* If filter is active, temporarily disable */ -+ if(APCG(filters) != NULL) { -+ filters = APCG(filters); -+ APCG(filters) = NULL; -+ } ++ The user entry is pretty simple and not all that important for now. I will ++ concentrate on the file entries since that is what holds the actual compiled ++ opcode arrays along with the functions and classes required by the executor. + -+ /* If cache_by_default is off, temporarily enable */ -+ if(!APCG(cache_by_default)) { -+ cache_by_default = APCG(cache_by_default); -+ APCG(cache_by_default) = 1; -+ } ++ apc_cache_make_file_entry() in apc_cache.c shows how an entry is constructed. ++ The main thing to understand here is that we need more than just the opcode ++ array, we also need the functions and classes created by the compiler when it ++ created the opcode array. As far as the executor is concerned, it doesn't know ++ that it isn't operating in normal mode being called right after the parse/compile ++ phase, so we need to recreate everything so it looks exactly like it would at ++ that point. + -+ /* Replace function/class tables to avoid namespace conflicts */ -+ zend_hash_init_ex(&cg_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); -+ cg_orig_function_table = CG(function_table); -+ CG(function_table) = &cg_function_table; -+ zend_hash_init_ex(&cg_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); -+ cg_orig_class_table = CG(class_table); -+ CG(class_table) = &cg_class_table; -+ zend_hash_init_ex(&eg_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); -+ eg_orig_function_table = EG(function_table); -+ EG(function_table) = &eg_function_table; -+ zend_hash_init_ex(&eg_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); -+ eg_orig_class_table = EG(class_table); -+ EG(class_table) = &eg_class_table; -+ -+ /* Compile the file, loading it into the cache */ -+ file_handle.type = ZEND_HANDLE_FILENAME; -+ file_handle.filename = filename; -+ file_handle.free_filename = 0; -+ file_handle.opened_path = NULL; -+ zend_try { -+ op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC); -+ } zend_catch { -+ apc_eprint("Error compiling %s in apc_compile_file.", filename); -+ op_array = NULL; -+ } zend_end_try(); ++7. my_compile_file() and apc_compile.c + -+ /* Return class/function tables to previous states, destroy temp tables */ -+ CG(function_table) = cg_orig_function_table; -+ zend_hash_destroy(&cg_function_table); -+ CG(class_table) = cg_orig_class_table; -+ zend_hash_destroy(&cg_class_table); -+ EG(function_table) = eg_orig_function_table; -+ zend_hash_destroy(&eg_function_table); -+ EG(class_table) = eg_orig_class_table; -+ zend_hash_destroy(&eg_class_table); -+ -+ /* Restore global settings */ -+ APCG(slam_defense) = slam_defense; -+ APCG(filters) = filters; -+ APCG(cache_by_default) = cache_by_default; ++ my_compile_file() in apc_main.c controls where we get the opcodes from. If ++ the user-specified filters exclude the file from being cached, then we just ++ call the original compile function and return. Otherwise we fetch the request ++ time from Apache to avoid an extra syscall, create the key so we can look up ++ the file in the cache. If we find it we stick it on a local stack which we ++ use at cleanup time to make sure we return everything back to normal after a ++ request and call cached_compile() which installs the functions and classes ++ associated with the op_array in this entry and then copy the op_array down ++ into our memory space for execution. + -+ if(op_array == NULL) { RETURN_FALSE; } ++ If we didn't find the file in the cache, we need to compile it and insert it. ++ To compile it we simply call the original compile function: + -+ /* Free up everything */ -+ zend_destroy_file_handle(&file_handle TSRMLS_CC); -+#ifdef ZEND_ENGINE_2 -+ destroy_op_array(op_array TSRMLS_CC); -+#else -+ destroy_op_array(op_array); -+#endif -+ efree(op_array); ++ op_array = old_compile_file(h, type TSRMLS_CC); + -+ RETURN_TRUE; -+} -+/* }}} */ ++ To do the insert we need to copy the functions, classes and the opcode array ++ the compile phase created into shared memory. This all happens in apc_compile.c ++ in the apc_copy_op_array(), apc_copy_new_functions() and apc_copy_new_classes() ++ functions. Then we make the file entry and do the insert. Both of these ++ operations were described in the previous section. + -+/* {{{ apc_functions[] */ -+function_entry apc_functions[] = { -+ PHP_FE(apc_cache_info, NULL) -+ PHP_FE(apc_clear_cache, NULL) -+ PHP_FE(apc_sma_info, NULL) -+ PHP_FE(apc_store, NULL) -+ PHP_FE(apc_fetch, NULL) -+ PHP_FE(apc_delete, NULL) -+ PHP_FE(apc_define_constants, NULL) -+ PHP_FE(apc_load_constants, NULL) -+ PHP_FE(apc_compile_file, NULL) -+ {NULL, NULL, NULL} -+}; -+/* }}} */ ++8. The Optimizer ++ ++ The optimizer has been deprecated. + -+/* {{{ module definition structure */ ++If you made it to the end of this, you should have a pretty good idea of where things are in ++the code. I skimmed over a lot of things, so plan on spending some time reading through the code. + -+zend_module_entry apc_module_entry = { -+ STANDARD_MODULE_HEADER, -+ "apc", -+ apc_functions, -+ PHP_MINIT(apc), -+ PHP_MSHUTDOWN(apc), -+ PHP_RINIT(apc), -+ PHP_RSHUTDOWN(apc), -+ PHP_MINFO(apc), -+ APC_VERSION, -+ STANDARD_MODULE_PROPERTIES -+}; +diff -Naur a/ext/apc/tests/apc_001.phpt b/ext/apc/tests/apc_001.phpt +--- a/ext/apc/tests/apc_001.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_001.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,32 @@ ++--TEST-- ++APC: apc_store/fetch with strings ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ | -+ | George Schlossnagle | -+ | Rasmus Lerdorf | -+ +----------------------------------------------------------------------+ ++apc_store('foo\x00bar', $foo); ++$bar = apc_fetch('foo\x00bar'); ++var_dump($bar); + -+ 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. ++?> ++===DONE=== ++ ++--EXPECTF-- ++string(11) "hello world" ++string(11) "hello world" ++string(4) "nice" ++string(11) "hello world" ++===DONE=== +diff -Naur a/ext/apc/tests/apc_002.phpt b/ext/apc/tests/apc_002.phpt +--- a/ext/apc/tests/apc_002.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_002.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,34 @@ ++--TEST-- ++APC: apc_store/fetch with objects ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++a = true; ++var_dump($bar); + -+ */ ++?> ++===DONE=== ++ ++--EXPECTF-- ++object(foo)#%d (0) { ++} ++object(foo)#%d (0) { ++} ++object(foo)#%d (1) { ++ ["a"]=> ++ bool(true) ++} ++===DONE=== +diff -Naur a/ext/apc/tests/apc_003b.phpt b/ext/apc/tests/apc_003b.phpt +--- a/ext/apc/tests/apc_003b.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_003b.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,117 @@ ++--TEST-- ++APC: apc_store/fetch with objects (php 5.3) ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++a = true; ++var_dump($bar); + -+#ifndef PHP_APC_H -+#define PHP_APC_H ++class bar extends foo ++{ ++ public $pub = 'bar'; ++ protected $pro = 'bar'; ++ private $pri = 'bar'; // we don't see this, we'd need php 5.1 new serialization ++ ++ function __construct() ++ { ++ $this->bar = true; ++ } ++ ++ function change() ++ { ++ $this->pri = 'mod'; ++ } ++} + -+#include "apc_php.h" -+#include "apc_globals.h" ++class baz extends bar ++{ ++ private $pri = 'baz'; + -+extern zend_module_entry apc_module_entry; -+#define apc_module_ptr &apc_module_entry ++ function __construct() ++ { ++ parent::__construct(); ++ $this->baz = true; ++ } ++} + -+#define phpext_apc_ptr apc_module_ptr ++$baz = new baz; ++var_dump($baz); ++$baz->change(); ++var_dump($baz); ++apc_store('baz', $baz); ++unset($baz); ++var_dump(apc_fetch('baz')); + -+#endif /* PHP_APC_H */ ++?> ++===DONE=== ++ ++--EXPECTF-- ++object(foo)#%d (0) { ++} ++object(foo)#%d (0) { ++} ++object(foo)#%d (1) { ++ ["a"]=> ++ bool(true) ++} ++object(baz)#%d (6) { ++ ["pri":"baz":private]=> ++ string(3) "baz" ++ ["pub"]=> ++ string(3) "bar" ++ ["pro":protected]=> ++ string(3) "bar" ++ ["pri":"bar":private]=> ++ string(3) "bar" ++ ["bar"]=> ++ bool(true) ++ ["baz"]=> ++ bool(true) ++} ++object(baz)#%d (6) { ++ ["pri":"baz":private]=> ++ string(3) "baz" ++ ["pub"]=> ++ string(3) "bar" ++ ["pro":protected]=> ++ string(3) "bar" ++ ["pri":"bar":private]=> ++ string(3) "mod" ++ ["bar"]=> ++ bool(true) ++ ["baz"]=> ++ bool(true) ++} ++object(baz)#%d (6) { ++ ["pri":"baz":private]=> ++ string(3) "baz" ++ ["pub"]=> ++ string(3) "bar" ++ ["pro":protected]=> ++ string(3) "bar" ++ ["pri":"bar":private]=> ++ string(3) "mod" ++ ["bar"]=> ++ bool(true) ++ ["baz"]=> ++ bool(true) ++} ++===DONE=== +diff -Naur a/ext/apc/tests/apc_003.phpt b/ext/apc/tests/apc_003.phpt +--- a/ext/apc/tests/apc_003.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_003.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,117 @@ ++--TEST-- ++APC: apc_store/fetch with objects (php pre-5.3) ++--SKIPIF-- ++= 0) { ++ echo "skip\n"; ++ } ++?> ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++a = true; ++var_dump($bar); + -+This is a rapidly written braindump of how APC currently works in the -+form of a quick-start guide to start hacking on APC. ++class bar extends foo ++{ ++ public $pub = 'bar'; ++ protected $pro = 'bar'; ++ private $pri = 'bar'; // we don't see this, we'd need php 5.1 new serialization ++ ++ function __construct() ++ { ++ $this->bar = true; ++ } ++ ++ function change() ++ { ++ $this->pri = 'mod'; ++ } ++} + -+1. Install and use APC a bit so you know what it does from the end-user's -+ perspective. -+ user-space functions are all explained here: ++class baz extends bar ++{ ++ private $pri = 'baz'; + -+2. Grab the current APC code from CVS: -+ -+ cvs -d:pserver:cvsread@cvs.php.net:/repository login -+ Password: phpfi -+ cvs -d:pserver:cvsread@cvs.php.net:/repository co pecl/apc ++ function __construct() ++ { ++ parent::__construct(); ++ $this->baz = true; ++ } ++} + -+ apc/php_apc.c has most of the code for the user-visible stuff. It is -+ also a regular PHP extension in the sense that there are MINIT, MINFO, -+ MSHUTDOWN, RSHUTDOWN, etc. functions. ++$baz = new baz; ++var_dump($baz); ++$baz->change(); ++var_dump($baz); ++apc_store('baz', $baz); ++unset($baz); ++var_dump(apc_fetch('baz')); + -+3. Build it. ++?> ++===DONE=== ++ ++--EXPECTF-- ++object(foo)#%d (0) { ++} ++object(foo)#%d (0) { ++} ++object(foo)#%d (1) { ++ ["a"]=> ++ bool(true) ++} ++object(baz)#%d (6) { ++ ["pri:private"]=> ++ string(3) "baz" ++ ["pub"]=> ++ string(3) "bar" ++ ["pro:protected"]=> ++ string(3) "bar" ++ ["pri:private"]=> ++ string(3) "bar" ++ ["bar"]=> ++ bool(true) ++ ["baz"]=> ++ bool(true) ++} ++object(baz)#%d (6) { ++ ["pri:private"]=> ++ string(3) "baz" ++ ["pub"]=> ++ string(3) "bar" ++ ["pro:protected"]=> ++ string(3) "bar" ++ ["pri:private"]=> ++ string(3) "mod" ++ ["bar"]=> ++ bool(true) ++ ["baz"]=> ++ bool(true) ++} ++object(baz)#%d (6) { ++ ["pri:private"]=> ++ string(3) "baz" ++ ["pub"]=> ++ string(3) "bar" ++ ["pro:protected"]=> ++ string(3) "bar" ++ ["pri:private"]=> ++ string(3) "mod" ++ ["bar"]=> ++ bool(true) ++ ["baz"]=> ++ bool(true) ++} ++===DONE=== +diff -Naur a/ext/apc/tests/apc_004.phpt b/ext/apc/tests/apc_004.phpt +--- a/ext/apc/tests/apc_004.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_004.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,38 @@ ++--TEST-- ++APC: apc_store/fetch with bools ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++bool(false) ++bool(false) ++bool(false) ++bool(true) ++bool(false) ++bool(false) ++bool(false) ++===DONE=== +diff -Naur a/ext/apc/tests/apc_005.phpt b/ext/apc/tests/apc_005.phpt +--- a/ext/apc/tests/apc_005.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_005.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,50 @@ ++--TEST-- ++APC: apc_store/fetch with arrays of objects ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++segsize and the number -+ of bytes available in header->avail. ++$bar = apc_fetch('foo'); ++var_dump($foo); ++var_dump($bar); + -+ After the header comes a bit of a hack. A zero-sized block is inserted just -+ to make things easier later on. And then a huge block that is basically -+ the size of the entire segment minus the two (for the 0-sized block, and this one) -+ block headers. ++?> ++===DONE=== ++ ++--EXPECTF-- ++array(2) { ++ [0]=> ++ object(stdClass)#1 (0) { ++ } ++ [1]=> ++ object(stdClass)#2 (0) { ++ } ++} ++array(2) { ++ [0]=> ++ object(stdClass)#1 (0) { ++ } ++ [1]=> ++ object(stdClass)#2 (0) { ++ } ++} ++array(2) { ++ [0]=> ++ object(stdClass)#3 (0) { ++ } ++ [1]=> ++ object(stdClass)#4 (0) { ++ } ++} ++===DONE=== +diff -Naur a/ext/apc/tests/apc_006.phpt b/ext/apc/tests/apc_006.phpt +--- a/ext/apc/tests/apc_006.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_006.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,73 @@ ++--TEST-- ++APC: apc_store/fetch reference test ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++apc.serializer=default ++report_memleaks=0 ++--FILE-- ++segsize = sma_segsize; -+ header->avail = sma_segsize - sizeof(header_t) - sizeof(block_t) - alignword(sizeof(int)); -+ memset(&header->lock,0,sizeof(header->lock)); -+ sma_lock = &header->lock; -+ block = BLOCKAT(sizeof(header_t)); -+ block->size = 0; -+ block->next = sizeof(header_t) + sizeof(block_t); -+ block = BLOCKAT(block->next); -+ block->size = header->avail; -+ block->next = 0; ++?> ++===DONE=== ++ ++--EXPECTF-- ++array(9) refcount(2){ ++ [0]=> ++ string(1) "a" refcount(1) ++ [1]=> ++ &array(1) refcount(2){ ++ [0]=> ++ string(1) "c" refcount(1) ++ } ++ [2]=> ++ &array(1) refcount(2){ ++ [0]=> ++ string(1) "c" refcount(1) ++ } ++ [3]=> ++ &string(1) "d" refcount(3) ++ [4]=> ++ &string(1) "d" refcount(3) ++ [5]=> ++ &string(1) "d" refcount(3) ++ [6]=> ++ string(1) "e" refcount(2) ++ [7]=> ++ string(1) "e" refcount(2) ++ [8]=> ++ &array(2) refcount(2){ ++ [0]=> ++ string(1) "f" refcount(1) ++ [1]=> ++ &array(2) refcount(2){ ++ [0]=> ++ string(1) "f" refcount(1) ++ [1]=> ++ *RECURSION* ++ } ++ } ++} ++===DONE=== +diff -Naur a/ext/apc/tests/apc_007.phpt b/ext/apc/tests/apc_007.phpt +--- a/ext/apc/tests/apc_007.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_007.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,46 @@ ++--TEST-- ++APC: apc_inc/apc_dec test ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++$foobar = 2 ++$foobar += 1 = 3 ++$foobar += 10 = 13 ++$foobar -= 1 = 12 ++$foobar -= 10 = 2 ++$f__bar += 1 = fail ++$perfection -= 1 = epic fail ++$foobar += 1 = 3 ++pass by ref success 1 ++$foobar -= 1 = 2 ++pass by ref success 1 ++===DONE=== +diff -Naur a/ext/apc/tests/apc_008.phpt b/ext/apc/tests/apc_008.phpt +--- a/ext/apc/tests/apc_008.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_008.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,34 @@ ++--TEST-- ++APC: apc_cas test ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++$foobar = 2 ++$foobar == 1 ? 2 : 1 = fail ++$foobar == 2 ? 1 : 2 = ok ++$foobar = 1 ++$f__bar == 1 ? 2 : 1 = fail ++$perfection == 2 ? 1 : 2 = epic fail ++$foobar = 1 ++===DONE=== +diff -Naur a/ext/apc/tests/apc_009.phpt b/ext/apc/tests/apc_009.phpt +--- a/ext/apc/tests/apc_009.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_009.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,97 @@ ++--TEST-- ++APC: apc_delete_file test ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++apc.stat=On ++report_memleaks=0 ++--FILE-- ++= to the requested size. -+ The first call to apc_sma_allocate() will hit the second block. We then -+ chop up that block so it looks like this: ++file_put_contents(dirname(__FILE__).'/apc_009-1.php', '| block | -+ +--------+-------+ +-------------------------+ ++apc_compile_file($files[0]); ++$it = new APCIterator('file'); ++apc_delete_file($it); ++check_file($files[0]); + -+ And header->avail along with block->size of the remaining large -+ block are updated accordingly. The arrow there representing the -+ link which now points to a block with an offset further along in -+ the segment. ++var_dump(apc_compile_file(array($files[0], $files[1]))); ++check_file(array($files[0], $files[1])); + -+ When the block is freed using apc_sma_deallocate() the steps are -+ basically just reversed. The block is put back and then the deallocate -+ code looks at the block before and after to see if the block immediately -+ before and after are free and if so the blocks are combined. So you never -+ have 2 free blocks next to each other, apart from at the front with that -+ 0-sized dummy block. This mostly prevents fragmentation. I have been -+ toying with the idea of always allocating block at 2^n boundaries to make -+ it more likely that they will be re-used to cut down on fragmentation further. -+ That's what the POWER_OF_TWO_BLOCKSIZE you see in apc_sma.c is all about. -+ -+ Of course, anytime we fiddle with our shared memory segment we lock using -+ the locking macros, LOCK() and UNLOCK(). ++var_dump(apc_compile_file($files)); ++check_file($files); + -+ That should mostly take care of the low-level shared memory handling. ++function check_file($files) { + -+6. Next up is apc_main.c and apc_cache.c which implement the meat of the -+ cache logic. ++ if (!is_array($files)) { ++ $files = array($files); ++ } + -+ The apc_main.c file mostly calls functions in apc_sma.c to allocate memory -+ and apc_cache.c for actual cache manipulation. -+ -+ After the shared memory segment is created and the caches are initialized, -+ apc_module_init() installs the my_compile_file() function overriding Zend's -+ version. I'll talk about my_compile_file() and the rest of apc_compile.c -+ in the next section. For now I will stick with apc_main.c and apc_cache.c -+ and talk about the actual caches. A cache consists of a block of shared -+ memory returned by apc_sma_allocate() via apc_sma_malloc(). You will -+ notice references to apc_emalloc(). apc_emalloc() is just a thin wrapper -+ around PHP's own emalloc() function which allocates per-process memory from -+ PHP's pool-based memory allocator. Don't confuse apc_emalloc() and -+ apc_sma_malloc() as the first is per-process and the second is shared memory. ++ $info = apc_cache_info('file'); + -+ The cache is stored in/described by this struct allocated locally using -+ emalloc(): ++ foreach ($files as $file) { ++ $match = 0; ++ foreach($info['cache_list'] as $cached_file) { ++ if (stristr($cached_file['filename'], $file)) $match = 1; ++ } ++ if ($match) { ++ echo "$file Found File\n"; ++ } else { ++ echo "$file Not Found\n"; ++ } ++ } ++} + -+ struct apc_cache_t { -+ void* shmaddr; /* process (local) address of shared cache */ -+ header_t* header; /* cache header (stored in SHM) */ -+ slot_t** slots; /* array of cache slots (stored in SHM) */ -+ int num_slots; /* number of slots in cache */ -+ int gc_ttl; /* maximum time on GC list for a slot */ -+ int ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */ -+ }; ++?> ++===DONE=== ++ ++--CLEAN-- ++ ++--EXPECTF-- ++apc_009.php Found File ++apc_009.php Not Found ++apc_009.php Not Found ++apc_009.php Not Found ++array(0) { ++} ++apc_009.php Found File ++apc_009-1.php Found File ++ ++Parse error: syntax error, unexpected '!' in %s/apc_009-2.php on line 1 ++ ++Warning: apc_compile_file(): Error compiling apc_009-2.php in apc_compile_file. in %s/apc_009.php on line 29 ++ ++Warning: apc_compile_file(): Error compiling nofile.php in apc_compile_file. in %s/apc_009.php on line 29 ++array(2) { ++ ["apc_009-2.php"]=> ++ int(-1) ++ ["nofile.php"]=> ++ int(-1) ++} ++apc_009.php Found File ++apc_009-1.php Found File ++apc_009-2.php Not Found ++nofile.php Not Found ++===DONE=== +diff -Naur a/ext/apc/tests/apc_010.phpt b/ext/apc/tests/apc_010.phpt +--- a/ext/apc/tests/apc_010.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_010.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,83 @@ ++--TEST-- ++APC: apc_store/fetch/add with array of key/value pairs. ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++array(0) { ++} ++array(4) { ++ ["key1"]=> ++ string(6) "value1" ++ ["key2"]=> ++ string(6) "value2" ++ ["key3"]=> ++ array(2) { ++ [0]=> ++ string(7) "value3a" ++ [1]=> ++ string(7) "value3b" ++ } ++ ["key4"]=> ++ int(4) ++} ++array(2) { ++ ["key1"]=> ++ string(6) "value1" ++ ["key3"]=> ++ array(2) { ++ [0]=> ++ string(7) "value3a" ++ [1]=> ++ string(7) "value3b" ++ } ++} ++array(2) { ++ ["key1"]=> ++ int(-1) ++ ["key3"]=> ++ int(-1) ++} ++array(4) { ++ ["key1"]=> ++ string(6) "value1" ++ ["key2"]=> ++ string(6) "value2" ++ ["key3"]=> ++ array(2) { ++ [0]=> ++ string(7) "value3a" ++ [1]=> ++ string(7) "value3b" ++ } ++ ["key4"]=> ++ int(4) ++} ++===DONE=== +diff -Naur a/ext/apc/tests/apc53_001.phpt b/ext/apc/tests/apc53_001.phpt +--- a/ext/apc/tests/apc53_001.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc53_001.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,33 @@ ++--TEST-- ++APC: classes with namespaces (php 5.3) ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++object(Foo\Bar\Baz)#1 (3) { ++ ["i"]=> ++ int(1) ++ ["f":protected]=> ++ float(3.14) ++ ["s":"Foo\Bar\Baz":private]=> ++ string(11) "hello world" ++} ++===DONE=== +diff -Naur a/ext/apc/tests/apc53_002.phpt b/ext/apc/tests/apc53_002.phpt +--- a/ext/apc/tests/apc53_002.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc53_002.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,47 @@ ++--TEST-- ++APC: global spaces (php 5.3) ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++foo(); ++var_dump(Foo\Bar\sort()); ++?> ++===DONE=== ++ ++--EXPECTF-- ++array(4) { ++ [0]=> ++ int(1) ++ [1]=> ++ int(2) ++ [2]=> ++ int(3) ++ [3]=> ++ int(4) ++} ++array(4) { ++ [0]=> ++ int(1) ++ [1]=> ++ int(2) ++ [2]=> ++ int(3) ++ [3]=> ++ int(4) ++} ++string(8) "IT WORKS" ++===DONE=== +diff -Naur a/ext/apc/tests/apc53_003.phpt b/ext/apc/tests/apc53_003.phpt +--- a/ext/apc/tests/apc53_003.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc53_003.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,31 @@ ++--TEST-- ++APC: anonymous functions (php 5.3) ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++slots[hash(key) % cache->num_slots]; ++$greet('World'); ++$greet('PHP'); + -+ cache->slots is our array of slots in the segment. hash() is simply: ++?> ++===DONE=== ++ ++--EXPECTF-- ++Hello World ++Hello PHP ++===DONE=== +diff -Naur a/ext/apc/tests/apc53_004.phpt b/ext/apc/tests/apc53_004.phpt +--- a/ext/apc/tests/apc53_004.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc53_004.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,33 @@ ++--TEST-- ++APC: closures (php 5.3) ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++double of 9 is 18 ++triple of 4 is 12 ++===DONE=== +diff -Naur a/ext/apc/tests/apc53_005.phpt b/ext/apc/tests/apc53_005.phpt +--- a/ext/apc/tests/apc53_005.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc53_005.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,35 @@ ++--TEST-- ++APC: goto (php 5.3) ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++1 ++2 ++4 ++5 ++7 ++8 ++10 ++===DONE=== +diff -Naur a/ext/apc/tests/apc_bin_001.phpt b/ext/apc/tests/apc_bin_001.phpt +--- a/ext/apc/tests/apc_bin_001.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_bin_001.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,24 @@ ++--TEST-- ++APC: bindump user cache ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++bool(false) ++string(9) "testvalue" ++===DONE=== +diff -Naur a/ext/apc/tests/apc_bin_002-1.inc b/ext/apc/tests/apc_bin_002-1.inc +--- a/ext/apc/tests/apc_bin_002-1.inc 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_bin_002-1.inc 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,42 @@ ++key.data.file, key.data.file)) { -+ /* If existing slot for the same device+inode is different, remove it and insert the new version */ -+ if ((*slot)->key.mtime != key.mtime) { -+ remove_slot(cache, slot); -+ break; -+ } -+ UNLOCK(cache); -+ return 0; -+ } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { -+ remove_slot(cache, slot); -+ continue; -+ } -+ slot = &(*slot)->next; -+ } ++echo "class static method: ".my_class::my_static_method()."\n"; ++echo "class dynamic method: ".$my_class->my_method()."\n"; ++echo "class static property: ".my_class::$my_static_property."\n"; ++echo "class dynamic property: ".$my_class->my_property."\n"; ++echo "class constant: ".my_class::my_constant."\n"; ++echo "\n"; ++echo "inherited class static method: ".my_i_class::my_static_method()."\n"; ++echo "inherited class dynamic method: ".$my_i_class->my_method()."\n"; ++echo "inherited class static property: ".my_i_class::$my_static_property."\n"; ++echo "inherited class dynamic property: ".$my_i_class->my_property."\n"; ++echo "inherited class constant: ".my_i_class::my_constant."\n"; ++echo "\n"; + -+ That first key_equals() check sees if we have an exact match meaning the file -+ is already in the cache. Since we try to find the file in the cache before doing -+ an insert, this will generally only happen if another process managed to beat us -+ to inserting it. If we have a newer version of the file at this point we remove -+ it an insert the new version. If our version is not newer we just return without -+ doing anything. + -+ While walking the linked list we also check to see if the cache has a TTL defined. -+ If while walking the linked list we see a slot that has expired, we remove it -+ since we are right there looking at it. This is the only place we remove stale -+ entries unless the shared memory segment fills up and we force a full expunge via -+ apc_cache_expunge(). apc_cache_expunge() walks the entire slots array and walks -+ down every linked list removing stale slots to free up room. This is obviously -+ slow and thus only happens when we have run out of room. + -+ apc_cache_find() simply hashes and returns the entry if it is there. If it is there -+ but older than the mtime in the entry we are looking for, we delete the one that is -+ there and return indicating we didn't find it. ++function my_function() { return "Success"; } + -+ Next we need to understand what an actual cache entry looks like. Have a look at -+ apc_cache.h for the structs. I sort of glossed over the key part earlier saying -+ that we just used the device+inode to find a hash slot. It is actually a bit more -+ complex than that because we have two kinds of caches. We have the standard file -+ cache containing opcode arrays, but we also have a user-controlled cache that the -+ user can insert whatever they want into via apc_store(). For the user cache we -+ obviously don't have a device+inode. The actual identifier is provided by the user -+ as a char *. So the key is actually a union that looks like this: + -+ typedef union _apc_cache_key_data_t { -+ struct { -+ int device; /* the filesystem device */ -+ int inode; /* the filesystem inode */ -+ } file; -+ struct { -+ char *identifier; -+ } user; -+ } apc_cache_key_data_t; ++class my_class { ++ static $my_static_property = "Success"; ++ var $my_property = "Success"; ++ const my_constant = "Success"; ++ static function my_static_method() { return "Success"; } ++ function my_method() { return "Success"; } ++} + -+ struct apc_cache_key_t { -+ apc_cache_key_data_t data; -+ int mtime; /* the mtime of this cached entry */ -+ }; ++class my_i_class extends my_class { ++ function dummy() { return 1; } ++} + -+ And we have two sets of functions to do inserts and finds. apc_cache_user_find() -+ and apc_cache_user_insert() operate on the user cache. +diff -Naur a/ext/apc/tests/apc_bin_002-2.inc b/ext/apc/tests/apc_bin_002-2.inc +--- a/ext/apc/tests/apc_bin_002-2.inc 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_bin_002-2.inc 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,5 @@ ++ +diff -Naur a/ext/apc/tests/apc_bin_002.phpt b/ext/apc/tests/apc_bin_002.phpt +--- a/ext/apc/tests/apc_bin_002.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/apc_bin_002.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,53 @@ ++--TEST-- ++APC: bindump file cache part 1 ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.stat=0 ++apc.cache_by_default=1 ++apc.filters= ++report_memleaks = Off ++--FILE-- ++ ++===DONE=== ++ ++--EXPECTF-- ++apc bindump 002 test ++ ++global scope execution: Success + -+ If we didn't find the file in the cache, we need to compile it and insert it. -+ To compile it we simply call the original compile function: ++function execution: Success + -+ op_array = old_compile_file(h, type TSRMLS_CC); ++class static method: Success ++class dynamic method: Success ++class static property: Success ++class dynamic property: Success ++class constant: Success + -+ To do the insert we need to copy the functions, classes and the opcode array -+ the compile phase created into shared memory. This all happens in apc_compile.c -+ in the apc_copy_op_array(), apc_copy_new_functions() and apc_copy_new_classes() -+ functions. Then we make the file entry and do the insert. Both of these -+ operations were described in the previous section. ++inherited class static method: Success ++inherited class dynamic method: Success ++inherited class static property: Success ++inherited class dynamic property: Success ++inherited class constant: Success + -+8. The Optimizer -+ -+ The optimizer has been deprecated. ++===DONE=== +diff -Naur a/ext/apc/tests/iterator_001.phpt b/ext/apc/tests/iterator_001.phpt +--- a/ext/apc/tests/iterator_001.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/iterator_001.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,110 @@ ++--TEST-- ++APC: APCIterator general ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++$value) { ++ $vals[$key] = $value['key']; ++} ++ksort($vals); ++var_dump($vals); + -Index: php-5.2.3/ext/apc/tests/apc_001.phpt -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/tests/apc_001.phpt 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,27 @@ ++?> ++===DONE=== ++ ++--EXPECT-- ++array(41) { ++ ["key0"]=> ++ string(4) "key0" ++ ["key1"]=> ++ string(4) "key1" ++ ["key10"]=> ++ string(5) "key10" ++ ["key11"]=> ++ string(5) "key11" ++ ["key12"]=> ++ string(5) "key12" ++ ["key13"]=> ++ string(5) "key13" ++ ["key14"]=> ++ string(5) "key14" ++ ["key15"]=> ++ string(5) "key15" ++ ["key16"]=> ++ string(5) "key16" ++ ["key17"]=> ++ string(5) "key17" ++ ["key18"]=> ++ string(5) "key18" ++ ["key19"]=> ++ string(5) "key19" ++ ["key2"]=> ++ string(4) "key2" ++ ["key20"]=> ++ string(5) "key20" ++ ["key21"]=> ++ string(5) "key21" ++ ["key22"]=> ++ string(5) "key22" ++ ["key23"]=> ++ string(5) "key23" ++ ["key24"]=> ++ string(5) "key24" ++ ["key25"]=> ++ string(5) "key25" ++ ["key26"]=> ++ string(5) "key26" ++ ["key27"]=> ++ string(5) "key27" ++ ["key28"]=> ++ string(5) "key28" ++ ["key29"]=> ++ string(5) "key29" ++ ["key3"]=> ++ string(4) "key3" ++ ["key30"]=> ++ string(5) "key30" ++ ["key31"]=> ++ string(5) "key31" ++ ["key32"]=> ++ string(5) "key32" ++ ["key33"]=> ++ string(5) "key33" ++ ["key34"]=> ++ string(5) "key34" ++ ["key35"]=> ++ string(5) "key35" ++ ["key36"]=> ++ string(5) "key36" ++ ["key37"]=> ++ string(5) "key37" ++ ["key38"]=> ++ string(5) "key38" ++ ["key39"]=> ++ string(5) "key39" ++ ["key4"]=> ++ string(4) "key4" ++ ["key40"]=> ++ string(5) "key40" ++ ["key5"]=> ++ string(4) "key5" ++ ["key6"]=> ++ string(4) "key6" ++ ["key7"]=> ++ string(4) "key7" ++ ["key8"]=> ++ string(4) "key8" ++ ["key9"]=> ++ string(4) "key9" ++} ++===DONE=== +diff -Naur a/ext/apc/tests/iterator_002.phpt b/ext/apc/tests/iterator_002.phpt +--- a/ext/apc/tests/iterator_002.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/iterator_002.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,36 @@ +--TEST-- -+APC: apc_store/fetch with strings ++APC: APCIterator regex +--SKIPIF-- + +--INI-- @@ -14158,29 +20594,37 @@ Index: php-5.2.3/ext/apc/tests/apc_001.phpt +--FILE-- +$value) { ++ $vals[$key] = $value['key']; ++} ++ksort($vals); ++var_dump($vals); + +?> +===DONE=== + -+--EXPECTF-- -+string(11) "hello world" -+string(11) "hello world" -+string(4) "nice" ++--EXPECT-- ++array(4) { ++ ["key10"]=> ++ string(5) "key10" ++ ["key20"]=> ++ string(5) "key20" ++ ["key30"]=> ++ string(5) "key30" ++ ["key40"]=> ++ string(5) "key40" ++} +===DONE=== -Index: php-5.2.3/ext/apc/tests/apc_002.phpt -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/tests/apc_002.phpt 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,34 @@ +diff -Naur a/ext/apc/tests/iterator_003.phpt b/ext/apc/tests/iterator_003.phpt +--- a/ext/apc/tests/iterator_003.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/iterator_003.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,110 @@ +--TEST-- -+APC: apc_store/fetch with objects ++APC: APCIterator chunk size +--SKIPIF-- + +--INI-- @@ -14190,36 +20634,151 @@ Index: php-5.2.3/ext/apc/tests/apc_002.phpt +--FILE-- +a = true; -+var_dump($bar); ++$it = new APCIterator('user', NULL, APC_ITER_ALL, 10); ++for($i = 0; $i < 41; $i++) { ++ apc_store("key$i", "value$i"); ++} ++foreach($it as $key=>$value) { ++ $vals[$key] = $value['key']; ++} ++ksort($vals); ++var_dump($vals); + +?> +===DONE=== + -+--EXPECTF-- -+object(foo)#%d (0) { ++--EXPECT-- ++array(41) { ++ ["key0"]=> ++ string(4) "key0" ++ ["key1"]=> ++ string(4) "key1" ++ ["key10"]=> ++ string(5) "key10" ++ ["key11"]=> ++ string(5) "key11" ++ ["key12"]=> ++ string(5) "key12" ++ ["key13"]=> ++ string(5) "key13" ++ ["key14"]=> ++ string(5) "key14" ++ ["key15"]=> ++ string(5) "key15" ++ ["key16"]=> ++ string(5) "key16" ++ ["key17"]=> ++ string(5) "key17" ++ ["key18"]=> ++ string(5) "key18" ++ ["key19"]=> ++ string(5) "key19" ++ ["key2"]=> ++ string(4) "key2" ++ ["key20"]=> ++ string(5) "key20" ++ ["key21"]=> ++ string(5) "key21" ++ ["key22"]=> ++ string(5) "key22" ++ ["key23"]=> ++ string(5) "key23" ++ ["key24"]=> ++ string(5) "key24" ++ ["key25"]=> ++ string(5) "key25" ++ ["key26"]=> ++ string(5) "key26" ++ ["key27"]=> ++ string(5) "key27" ++ ["key28"]=> ++ string(5) "key28" ++ ["key29"]=> ++ string(5) "key29" ++ ["key3"]=> ++ string(4) "key3" ++ ["key30"]=> ++ string(5) "key30" ++ ["key31"]=> ++ string(5) "key31" ++ ["key32"]=> ++ string(5) "key32" ++ ["key33"]=> ++ string(5) "key33" ++ ["key34"]=> ++ string(5) "key34" ++ ["key35"]=> ++ string(5) "key35" ++ ["key36"]=> ++ string(5) "key36" ++ ["key37"]=> ++ string(5) "key37" ++ ["key38"]=> ++ string(5) "key38" ++ ["key39"]=> ++ string(5) "key39" ++ ["key4"]=> ++ string(4) "key4" ++ ["key40"]=> ++ string(5) "key40" ++ ["key5"]=> ++ string(4) "key5" ++ ["key6"]=> ++ string(4) "key6" ++ ["key7"]=> ++ string(4) "key7" ++ ["key8"]=> ++ string(4) "key8" ++ ["key9"]=> ++ string(4) "key9" +} -+object(foo)#%d (0) { ++===DONE=== +diff -Naur a/ext/apc/tests/iterator_004.phpt b/ext/apc/tests/iterator_004.phpt +--- a/ext/apc/tests/iterator_004.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/iterator_004.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,36 @@ ++--TEST-- ++APC: APCIterator regex & chunk size & list ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++--FILE-- ++ -+ bool(true) ++foreach($it as $key=>$value) { ++ $vals[$key] = $value['key']; ++} ++ksort($vals); ++var_dump($vals); ++ ++?> ++===DONE=== ++ ++--EXPECT-- ++array(4) { ++ ["key10"]=> ++ string(5) "key10" ++ ["key20"]=> ++ string(5) "key20" ++ ["key30"]=> ++ string(5) "key30" ++ ["key40"]=> ++ string(5) "key40" +} +===DONE=== -Index: php-5.2.3/ext/apc/tests/apc_003.phpt -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/tests/apc_003.phpt 2007-07-30 10:52:17.000000000 -0500 +diff -Naur a/ext/apc/tests/iterator_005.phpt b/ext/apc/tests/iterator_005.phpt +--- a/ext/apc/tests/iterator_005.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/iterator_005.phpt 2012-07-20 00:10:35.000000000 +0200 @@ -0,0 +1,112 @@ +--TEST-- -+APC: apc_store/fetch with objects ++APC: APCIterator delete +--SKIPIF-- + +--INI-- @@ -14229,111 +20788,1712 @@ Index: php-5.2.3/ext/apc/tests/apc_003.phpt +--FILE-- +a = true; -+var_dump($bar); ++$vals = array(); ++$vals2 = array(); ++$it = new APCIterator('user', '/key[0-9]0/'); ++for($i = 0; $i < 41; $i++) { ++ apc_store("key$i", "value$i"); ++} ++apc_delete($it); ++$it2 = new APCIterator('user'); ++foreach($it as $key=>$value) { ++ $vals[$key] = $value['key']; ++} ++foreach($it2 as $key=>$value) { ++ $vals2[$key] = $value['key']; ++} ++ksort($vals2); ++var_dump($vals); ++var_dump($vals2); + -+class bar extends foo -+{ -+ public $pub = 'bar'; -+ protected $pro = 'bar'; -+ private $pri = 'bar'; // we don't see this, we'd need php 5.1 new serialization -+ -+ function __construct() -+ { -+ $this->bar = true; -+ } -+ -+ function change() -+ { -+ $this->pri = 'mod'; -+ } ++?> ++===DONE=== ++ ++--EXPECT-- ++array(0) { ++} ++array(37) { ++ ["key0"]=> ++ string(4) "key0" ++ ["key1"]=> ++ string(4) "key1" ++ ["key11"]=> ++ string(5) "key11" ++ ["key12"]=> ++ string(5) "key12" ++ ["key13"]=> ++ string(5) "key13" ++ ["key14"]=> ++ string(5) "key14" ++ ["key15"]=> ++ string(5) "key15" ++ ["key16"]=> ++ string(5) "key16" ++ ["key17"]=> ++ string(5) "key17" ++ ["key18"]=> ++ string(5) "key18" ++ ["key19"]=> ++ string(5) "key19" ++ ["key2"]=> ++ string(4) "key2" ++ ["key21"]=> ++ string(5) "key21" ++ ["key22"]=> ++ string(5) "key22" ++ ["key23"]=> ++ string(5) "key23" ++ ["key24"]=> ++ string(5) "key24" ++ ["key25"]=> ++ string(5) "key25" ++ ["key26"]=> ++ string(5) "key26" ++ ["key27"]=> ++ string(5) "key27" ++ ["key28"]=> ++ string(5) "key28" ++ ["key29"]=> ++ string(5) "key29" ++ ["key3"]=> ++ string(4) "key3" ++ ["key31"]=> ++ string(5) "key31" ++ ["key32"]=> ++ string(5) "key32" ++ ["key33"]=> ++ string(5) "key33" ++ ["key34"]=> ++ string(5) "key34" ++ ["key35"]=> ++ string(5) "key35" ++ ["key36"]=> ++ string(5) "key36" ++ ["key37"]=> ++ string(5) "key37" ++ ["key38"]=> ++ string(5) "key38" ++ ["key39"]=> ++ string(5) "key39" ++ ["key4"]=> ++ string(4) "key4" ++ ["key5"]=> ++ string(4) "key5" ++ ["key6"]=> ++ string(4) "key6" ++ ["key7"]=> ++ string(4) "key7" ++ ["key8"]=> ++ string(4) "key8" ++ ["key9"]=> ++ string(4) "key9" +} ++===DONE=== +diff -Naur a/ext/apc/tests/iterator_006.phpt b/ext/apc/tests/iterator_006.phpt +--- a/ext/apc/tests/iterator_006.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/iterator_006.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,1536 @@ ++--TEST-- ++APC: APCIterator formats ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++apc.file_update_protection=0 ++apc.user_entries_hint=4096 ++--FILE-- ++baz = true; -+ } ++$it_array = array(); ++ ++foreach ($formats as $idx => $format) { ++ $it_array[$idx] = new APCIterator('user', NULL, $format); +} + -+$baz = new baz; -+var_dump($baz); -+$baz->change(); -+var_dump($baz); -+apc_store('baz', $baz); -+unset($baz); -+var_dump(apc_fetch('baz')); ++for($i = 0; $i < 11; $i++) { ++ apc_store("key$i", "value$i"); ++} ++ ++foreach ($it_array as $idx => $it) { ++ print_it($it, $idx); ++} ++ ++function print_it($it, $idx) { ++ echo "IT #$idx\n"; ++ echo "============================\n"; ++ foreach ($it as $key=>$value) { ++ var_dump($key); ++ var_dump($value); ++ } ++ echo "============================\n\n"; ++} + +?> +===DONE=== + +--EXPECTF-- -+object(foo)#%d (0) { ++IT #0 ++============================ ++string(5) "key10" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key0" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key1" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key2" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key3" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key4" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key5" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key6" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key7" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key8" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++string(4) "key9" ++array(1) { ++ ["type"]=> ++ string(4) "user" ++} ++============================ ++ ++IT #1 ++============================ ++string(5) "key10" ++array(1) { ++ ["key"]=> ++ string(5) "key10" ++} ++string(4) "key0" ++array(1) { ++ ["key"]=> ++ string(4) "key0" ++} ++string(4) "key1" ++array(1) { ++ ["key"]=> ++ string(4) "key1" ++} ++string(4) "key2" ++array(1) { ++ ["key"]=> ++ string(4) "key2" ++} ++string(4) "key3" ++array(1) { ++ ["key"]=> ++ string(4) "key3" ++} ++string(4) "key4" ++array(1) { ++ ["key"]=> ++ string(4) "key4" +} -+object(foo)#%d (0) { ++string(4) "key5" ++array(1) { ++ ["key"]=> ++ string(4) "key5" ++} ++string(4) "key6" ++array(1) { ++ ["key"]=> ++ string(4) "key6" +} -+object(foo)#%d (1) { -+ ["a"]=> -+ bool(true) ++string(4) "key7" ++array(1) { ++ ["key"]=> ++ string(4) "key7" +} -+object(baz)#%d (6) { -+ ["pri:private"]=> -+ string(3) "baz" -+ ["pub"]=> -+ string(3) "bar" -+ ["pro:protected"]=> -+ string(3) "bar" -+ ["pri:private"]=> -+ string(3) "bar" -+ ["bar"]=> -+ bool(true) -+ ["baz"]=> -+ bool(true) ++string(4) "key8" ++array(1) { ++ ["key"]=> ++ string(4) "key8" +} -+object(baz)#%d (6) { -+ ["pri:private"]=> -+ string(3) "baz" -+ ["pub"]=> -+ string(3) "bar" -+ ["pro:protected"]=> -+ string(3) "bar" -+ ["pri:private"]=> -+ string(3) "mod" -+ ["bar"]=> -+ bool(true) -+ ["baz"]=> -+ bool(true) ++string(4) "key9" ++array(1) { ++ ["key"]=> ++ string(4) "key9" +} -+object(baz)#%d (6) { -+ ["pri:private"]=> -+ string(3) "baz" -+ ["pub"]=> -+ string(3) "bar" -+ ["pro:protected"]=> -+ string(3) "bar" -+ ["pri:private"]=> -+ string(3) "mod" -+ ["bar"]=> -+ bool(true) -+ ["baz"]=> -+ bool(true) ++============================ ++ ++IT #2 ++============================ ++string(5) "key10" ++array(0) { ++} ++string(4) "key0" ++array(0) { ++} ++string(4) "key1" ++array(0) { ++} ++string(4) "key2" ++array(0) { +} ++string(4) "key3" ++array(0) { ++} ++string(4) "key4" ++array(0) { ++} ++string(4) "key5" ++array(0) { ++} ++string(4) "key6" ++array(0) { ++} ++string(4) "key7" ++array(0) { ++} ++string(4) "key8" ++array(0) { ++} ++string(4) "key9" ++array(0) { ++} ++============================ ++ ++IT #3 ++============================ ++string(5) "key10" ++array(0) { ++} ++string(4) "key0" ++array(0) { ++} ++string(4) "key1" ++array(0) { ++} ++string(4) "key2" ++array(0) { ++} ++string(4) "key3" ++array(0) { ++} ++string(4) "key4" ++array(0) { ++} ++string(4) "key5" ++array(0) { ++} ++string(4) "key6" ++array(0) { ++} ++string(4) "key7" ++array(0) { ++} ++string(4) "key8" ++array(0) { ++} ++string(4) "key9" ++array(0) { ++} ++============================ ++ ++IT #4 ++============================ ++string(5) "key10" ++array(0) { ++} ++string(4) "key0" ++array(0) { ++} ++string(4) "key1" ++array(0) { ++} ++string(4) "key2" ++array(0) { ++} ++string(4) "key3" ++array(0) { ++} ++string(4) "key4" ++array(0) { ++} ++string(4) "key5" ++array(0) { ++} ++string(4) "key6" ++array(0) { ++} ++string(4) "key7" ++array(0) { ++} ++string(4) "key8" ++array(0) { ++} ++string(4) "key9" ++array(0) { ++} ++============================ ++ ++IT #5 ++============================ ++string(5) "key10" ++array(1) { ++ ["value"]=> ++ string(7) "value10" ++} ++string(4) "key0" ++array(1) { ++ ["value"]=> ++ string(6) "value0" ++} ++string(4) "key1" ++array(1) { ++ ["value"]=> ++ string(6) "value1" ++} ++string(4) "key2" ++array(1) { ++ ["value"]=> ++ string(6) "value2" ++} ++string(4) "key3" ++array(1) { ++ ["value"]=> ++ string(6) "value3" ++} ++string(4) "key4" ++array(1) { ++ ["value"]=> ++ string(6) "value4" ++} ++string(4) "key5" ++array(1) { ++ ["value"]=> ++ string(6) "value5" ++} ++string(4) "key6" ++array(1) { ++ ["value"]=> ++ string(6) "value6" ++} ++string(4) "key7" ++array(1) { ++ ["value"]=> ++ string(6) "value7" ++} ++string(4) "key8" ++array(1) { ++ ["value"]=> ++ string(6) "value8" ++} ++string(4) "key9" ++array(1) { ++ ["value"]=> ++ string(6) "value9" ++} ++============================ ++ ++IT #6 ++============================ ++string(5) "key10" ++array(0) { ++} ++string(4) "key0" ++array(0) { ++} ++string(4) "key1" ++array(0) { ++} ++string(4) "key2" ++array(0) { ++} ++string(4) "key3" ++array(0) { ++} ++string(4) "key4" ++array(0) { ++} ++string(4) "key5" ++array(0) { ++} ++string(4) "key6" ++array(0) { ++} ++string(4) "key7" ++array(0) { ++} ++string(4) "key8" ++array(0) { ++} ++string(4) "key9" ++array(0) { ++} ++============================ ++ ++IT #7 ++============================ ++string(5) "key10" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key0" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key1" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key2" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key3" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key4" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key5" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key6" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key7" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key8" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++string(4) "key9" ++array(1) { ++ ["num_hits"]=> ++ int(0) ++} ++============================ ++ ++IT #8 ++============================ ++string(5) "key10" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key0" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key1" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key2" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key3" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key4" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key5" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key6" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key7" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key8" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++string(4) "key9" ++array(1) { ++ ["mtime"]=> ++ int(%d) ++} ++============================ ++ ++IT #9 ++============================ ++string(5) "key10" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key0" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key1" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key2" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key3" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key4" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key5" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key6" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key7" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key8" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++string(4) "key9" ++array(1) { ++ ["creation_time"]=> ++ int(%d) ++} ++============================ ++ ++IT #10 ++============================ ++string(5) "key10" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key0" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key1" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key2" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key3" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key4" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key5" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key6" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key7" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key8" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++string(4) "key9" ++array(1) { ++ ["deletion_time"]=> ++ int(0) ++} ++============================ ++ ++IT #11 ++============================ ++string(5) "key10" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key0" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key1" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key2" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key3" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key4" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key5" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key6" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key7" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key8" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++string(4) "key9" ++array(1) { ++ ["access_time"]=> ++ int(%d) ++} ++============================ ++ ++IT #12 ++============================ ++string(5) "key10" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key0" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key1" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key2" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key3" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key4" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key5" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key6" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key7" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key8" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++string(4) "key9" ++array(1) { ++ ["ref_count"]=> ++ int(0) ++} ++============================ ++ ++IT #13 ++============================ ++string(5) "key10" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key0" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key1" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key2" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key3" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key4" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key5" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key6" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key7" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key8" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key9" ++array(1) { ++ ["mem_size"]=> ++ int(%d) ++} ++============================ ++ ++IT #14 ++============================ ++string(5) "key10" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key0" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key1" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key2" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key3" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key4" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key5" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key6" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key7" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key8" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key9" ++array(1) { ++ ["ttl"]=> ++ int(0) ++} ++============================ ++ ++IT #15 ++============================ ++string(5) "key10" ++array(0) { ++} ++string(4) "key0" ++array(0) { ++} ++string(4) "key1" ++array(0) { ++} ++string(4) "key2" ++array(0) { ++} ++string(4) "key3" ++array(0) { ++} ++string(4) "key4" ++array(0) { ++} ++string(4) "key5" ++array(0) { ++} ++string(4) "key6" ++array(0) { ++} ++string(4) "key7" ++array(0) { ++} ++string(4) "key8" ++array(0) { ++} ++string(4) "key9" ++array(0) { ++} ++============================ ++ ++IT #16 ++============================ ++string(5) "key10" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(5) "key10" ++ ["value"]=> ++ string(7) "value10" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key0" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key0" ++ ["value"]=> ++ string(6) "value0" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key1" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key1" ++ ["value"]=> ++ string(6) "value1" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key2" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key2" ++ ["value"]=> ++ string(6) "value2" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key3" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key3" ++ ["value"]=> ++ string(6) "value3" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key4" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key4" ++ ["value"]=> ++ string(6) "value4" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key5" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key5" ++ ["value"]=> ++ string(6) "value5" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key6" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key6" ++ ["value"]=> ++ string(6) "value6" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key7" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key7" ++ ["value"]=> ++ string(6) "value7" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key8" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key8" ++ ["value"]=> ++ string(6) "value8" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++string(4) "key9" ++array(11) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key9" ++ ["value"]=> ++ string(6) "value9" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++ ["ttl"]=> ++ int(0) ++} ++============================ ++ ++IT #17 ++============================ ++string(5) "key10" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(5) "key10" ++ ["value"]=> ++ string(7) "value10" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key0" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key0" ++ ["value"]=> ++ string(6) "value0" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key1" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key1" ++ ["value"]=> ++ string(6) "value1" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key2" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key2" ++ ["value"]=> ++ string(6) "value2" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key3" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key3" ++ ["value"]=> ++ string(6) "value3" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key4" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key4" ++ ["value"]=> ++ string(6) "value4" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key5" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key5" ++ ["value"]=> ++ string(6) "value5" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key6" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key6" ++ ["value"]=> ++ string(6) "value6" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key7" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key7" ++ ["value"]=> ++ string(6) "value7" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key8" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key8" ++ ["value"]=> ++ string(6) "value8" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key9" ++array(10) { ++ ["type"]=> ++ string(4) "user" ++ ["key"]=> ++ string(4) "key9" ++ ["value"]=> ++ string(6) "value9" ++ ["num_hits"]=> ++ int(0) ++ ["mtime"]=> ++ int(%d) ++ ["creation_time"]=> ++ int(%d) ++ ["deletion_time"]=> ++ int(0) ++ ["access_time"]=> ++ int(%d) ++ ["ref_count"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++============================ ++ ++IT #18 ++============================ ++string(5) "key10" ++array(3) { ++ ["key"]=> ++ string(5) "key10" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key0" ++array(3) { ++ ["key"]=> ++ string(4) "key0" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key1" ++array(3) { ++ ["key"]=> ++ string(4) "key1" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key2" ++array(3) { ++ ["key"]=> ++ string(4) "key2" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key3" ++array(3) { ++ ["key"]=> ++ string(4) "key3" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key4" ++array(3) { ++ ["key"]=> ++ string(4) "key4" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key5" ++array(3) { ++ ["key"]=> ++ string(4) "key5" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key6" ++array(3) { ++ ["key"]=> ++ string(4) "key6" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key7" ++array(3) { ++ ["key"]=> ++ string(4) "key7" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key8" ++array(3) { ++ ["key"]=> ++ string(4) "key8" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++string(4) "key9" ++array(3) { ++ ["key"]=> ++ string(4) "key9" ++ ["num_hits"]=> ++ int(0) ++ ["mem_size"]=> ++ int(%d) ++} ++============================ ++ +===DONE=== -Index: php-5.2.3/ext/apc/tests/skipif.inc -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/tests/skipif.inc 2007-07-30 10:52:17.000000000 -0500 +diff -Naur a/ext/apc/tests/iterator_007.phpt b/ext/apc/tests/iterator_007.phpt +--- a/ext/apc/tests/iterator_007.phpt 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/iterator_007.phpt 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,36 @@ ++--TEST-- ++APC: APCIterator Overwriting the ctor ++--SKIPIF-- ++ ++--INI-- ++apc.enabled=1 ++apc.enable_cli=1 ++--FILE-- ++rewind(), ++ $obj->current(), ++ $obj->key(), ++ $obj->next(), ++ $obj->valid(), ++ $obj->getTotalHits(), ++ $obj->getTotalSize(), ++ $obj->getTotalCount(), ++ apc_delete($obj) ++); ++?> ++--EXPECTF-- ++bool(false) ++bool(false) ++bool(false) ++bool(false) ++bool(false) ++bool(false) ++bool(false) ++bool(false) ++bool(false) ++ +diff -Naur a/ext/apc/tests/php_5_3_ns.inc b/ext/apc/tests/php_5_3_ns.inc +--- a/ext/apc/tests/php_5_3_ns.inc 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/tests/php_5_3_ns.inc 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,18 @@ ++ -Index: php-5.2.3/ext/apc/TODO -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ php-5.2.3/ext/apc/TODO 2007-07-30 10:52:17.000000000 -0500 -@@ -0,0 +1,30 @@ +diff -Naur a/ext/apc/TODO b/ext/apc/TODO +--- a/ext/apc/TODO 1970-01-01 01:00:00.000000000 +0100 ++++ b/ext/apc/TODO 2012-07-20 00:10:35.000000000 +0200 +@@ -0,0 +1,35 @@ +Known Bugs + +1. Gallery2 doesn't work with PHP5+APC. There is something wrong @@ -14367,12 +22526,18 @@ Index: php-5.2.3/ext/apc/TODO + in the apc_store() function in php_apc.c but I am wondering if it needs to do more + than that. + -+Enhancements ++Windows ++ ++1. The following configurations (build arguments) have not been implemented yet + -+1. Some faster platform-specific locking mechanisms wouldd be nice. futex support -+ for the 2.6 Linux kernels, and/or x86-specific spinlock support. ++ (*) --enable-apc-mmap Memory mapping support ++ (*) --enable-apc-sem Semaphore locking support (FCNTL replacement) ++ (*) --enable-apc-phreadmutex Thread mutexes, while implemented we should probably rename the internals to thread ++ (*) --enable-apc-pthreadrwlocks Thread mutexes, read/write locking + -+2. The optimizer needs a lot of work. ++2. Non-blocking locks is not supported either + -+3. Assert() elimination in the optimizer when some debug flag somewhere isn't set. ++3. Update fileinfo to support stat info in a more portable way (see PECL #17903) + ++4. Check whether the signal handling needs to be enabled, and if it makes sense on Windows +\ Kein Zeilenumbruch am Dateiende.