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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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.c,v 3.17 2007/03/17 14:01:41 gopalv Exp $ */ + +#include "apc.h" +#include /* for POSIX regular expressions */ +#include "php.h" + +#define NELEMS(a) (sizeof(a)/sizeof((a)[0])) + +/* {{{ memory allocation wrappers */ + +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; +} + +void apc_efree(void* p) +{ + if (p == NULL) { + apc_eprint("apc_efree: attempt to free null pointer"); + } + free(p); +} + +char* apc_estrdup(const char* s) +{ + int len; + char* dup; + + 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; +} + +void* apc_xstrdup(const char* s, apc_malloc_t f) +{ + return s != NULL ? apc_xmemcpy(s, strlen(s)+1, f) : NULL; +} + +void* apc_xmemcpy(const void* p, size_t n, apc_malloc_t f) +{ + void* q; + + if (p != NULL && (q = f(n)) != NULL) { + memcpy(q, p, n); + return q; + } + return NULL; +} + +/* }}} */ + +/* {{{ console display functions */ + +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); + + time_t now; + char* buf; /* for ctime */ + + fflush(stdout); + + 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'; + + 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"); + + if (level == APC_ERROR) { + exit(2); + } +} + +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); +} + +void apc_wprint(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + my_log(APC_WARNING, fmt, args); + va_end(args); +} + +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); +#endif +} + +/* }}} */ + +/* {{{ string and text manipulation */ + +char* apc_append(const char* s, const char* t) +{ + int slen; + int tlen; + char* p; + + slen = strlen(s); + tlen = strlen(t); + + p = (char*) apc_emalloc((slen + tlen + 1) * sizeof(char)); + memcpy(p, s, slen); + memcpy(p + slen, t, tlen + 1); + + return p; +} + +char* apc_substr(const char* s, int start, int length) +{ + char* substr; + int src_len = strlen(s); + + /* bring start into range */ + if (start < 0) { + start = 0; + } + else if (start >= src_len) { + start = src_len - 1; + } + + /* 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); + 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; + + 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*)); + } + + /* save the current token */ + tokens[n] = apc_substr(s, cur, next-cur); + + tokens[++n] = NULL; + cur = next + 1; + } + + return tokens; +} + +/* }}} */ + +/* {{{ filesystem functions */ + +#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; + } + + 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; +} +#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(); + + assert(filename && fileinfo); + + if (IS_ABSOLUTE_PATH(filename, strlen(filename)) && apc_stat(filename, &fileinfo->st_buf) == 0) { + strncpy(fileinfo->fullpath, filename, MAXPATHLEN); + return 0; + } + + paths = apc_tokenize(path, DEFAULT_DIR_SEPARATOR); + if (!paths) + return -1; + + /* 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; + } + } + + /* 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_efree(paths); + + return found ? 0 : -1; +} + +/* }}} */ + +/* {{{ regular expression wrapper functions */ + +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; + + /* count the number of patterns in patterns */ + for (npat = 0; patterns[npat] != NULL; npat++) {} + + if (npat == 0) + return NULL; + + /* 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; + } + + /* 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); } + + regs[i]->reg = (regex_t*) apc_emalloc(sizeof(regex_t)); + + 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); + + return NULL; + } + } + + return (void*) regs; +} + +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_efree(regs); + } +} + +int apc_regex_match_array(void* p, const char* input) +{ + apc_regex** regs; + int i; + + if (!p) + return 0; + + 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); + + return 0; +} + +/* }}} */ + +/* {{{ 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) +{ + 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]; + } + + /* postconditioning */ + return ~crc; +} + +/* 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; + } + else { + crc >>= 1; + } + } + return crc; +} +#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_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 @@ +/* + +----------------------------------------------------------------------+ + | 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. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: apc_cache.c,v 3.140 2007/04/02 22:57:10 rasmus Exp $ */ + +#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" + +/* TODO: rehash when load factor exceeds threshold */ + +#define CHECK(p) { if ((p) == NULL) return NULL; } + +/* {{{ 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) +/* }}} */ + +/* {{{ hash */ +static unsigned int hash(apc_cache_key_t key) +{ + return key.data.file.device + key.data.file.inode; +} +/* }}} */ + +/* {{{ string_nhash_8 */ +static unsigned int string_nhash_8(const char *s, size_t len) +{ + 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)); + } + s = (const char *)iv; + for(len %= sizeof(unsigned int);len;len--) { + h += *(s++); + } + h ^= (h >> 13); + h ^= (h >> 7); + return h; +} +/* }}} */ + +/* {{{ make_slot */ +slot_t* make_slot(apc_cache_key_t key, apc_cache_entry_t* value, slot_t* next, time_t t) +{ + slot_t* p = apc_sma_malloc(sizeof(slot_t)); + if (!p) return NULL; + + 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; + } + 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; +} +/* }}} */ + +/* {{{ free_slot */ +static void free_slot(slot_t* slot) +{ + 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); +} +/* }}} */ + +/* {{{ remove_slot */ +static void remove_slot(apc_cache_t* cache, slot_t** slot) +{ + slot_t* dead = *slot; + *slot = (*slot)->next; + + 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; + } +} +/* }}} */ + +/* {{{ process_pending_removals */ +static void process_pending_removals(apc_cache_t* cache) +{ + slot_t** slot; + time_t now; + + /* This function scans the list of removed cache entries and deletes any + * entry whose reference count is zero (indicating that it is no longer + * being executed) or that has been on the pending list for more than + * cache->gc_ttl seconds (we issue a warning in the latter case). + */ + + if (!cache->header->deleted_list) + return; + + slot = &cache->header->deleted_list; + now = time(0); + + while (*slot != NULL) { + int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0; + + if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) { + slot_t* dead = *slot; + + if (dead->value->ref_count > 0) { + switch(dead->value->type) { + case APC_CACHE_ENTRY_FILE: + apc_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; + } + } +} +/* }}} */ + +/* {{{ prevent_garbage_collection */ +static void prevent_garbage_collection(apc_cache_entry_t* entry) +{ + /* set reference counts on zend objects to an arbitrarily high value to + * prevent garbage collection after execution */ + + enum { BIG_VALUE = 1000 }; + + if(entry->data.file.op_array) { + entry->data.file.op_array->refcount[0] = BIG_VALUE; + } + if (entry->data.file.functions) { + int i; + apc_function_t* fns = entry->data.file.functions; + for (i=0; fns[i].function != NULL; i++) { +#ifdef ZEND_ENGINE_2 + *(fns[i].function->op_array.refcount) = BIG_VALUE; +#else + fns[i].function->op_array.refcount[0] = BIG_VALUE; +#endif + } + } + 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 + } + } +} +/* }}} */ + +/* {{{ apc_cache_create */ +apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl) +{ + apc_cache_t* cache; + int cache_size; + int num_slots; + int i; + + num_slots = size_hint > 0 ? size_hint*2 : 2000; + + cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t)); + cache_size = sizeof(header_t) + num_slots*sizeof(slot_t*); + + cache->shmaddr = apc_sma_malloc(cache_size); + memset(cache->shmaddr, 0, cache_size); + + 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; + + 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; + } + + return cache; +} +/* }}} */ + +/* {{{ 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) +{ + int i; + + if(!cache) return; + + 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); + } + cache->slots[i] = NULL; + } + + cache->header->busy = 0; + UNLOCK(cache); +} +/* }}} */ + +/* {{{ apc_cache_expunge */ +void apc_cache_expunge(apc_cache_t* cache, time_t t) +{ + int i; + + if(!cache) return; + + 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 + */ + + 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); + } +} +/* }}} */ + +/* {{{ 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; + } + +#ifdef __DEBUG_APC__ + fprintf(stderr,"Inserting [%s]\n", value->data.file.filename); +#endif + + LOCK(cache); + process_pending_removals(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 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); + break; + } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) { + remove_slot(cache, slot); + continue; + } + } + } + slot = &(*slot)->next; + } + + if ((*slot = make_slot(key, value, *slot, t)) == NULL) { + UNLOCK(cache); + return -1; + } + + cache->header->mem_size += value->mem_size; + cache->header->num_entries++; + cache->header->num_inserts++; + + UNLOCK(cache); + return 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; + + if (!value) { + return 0; + } + + LOCK(cache); + process_pending_removals(cache); + + slot = &cache->slots[string_nhash_8(key.data.user.identifier, key.data.user.identifier_len) % cache->num_slots]; + + if (APCG(mem_size_ptr) != NULL) { + mem_size_ptr = APCG(mem_size_ptr); + APCG(mem_size_ptr) = NULL; + } + + 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; + } + slot = &(*slot)->next; + } + + if (mem_size_ptr != NULL) { + APCG(mem_size_ptr) = mem_size_ptr; + } + + 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++; + + UNLOCK(cache); + return 1; +} +/* }}} */ + +/* {{{ apc_cache_find_slot */ +slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t) +{ + 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; + } + 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; +} +/* }}} */ + +/* {{{ apc_cache_user_find */ +apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t) +{ + slot_t** slot; + volatile apc_cache_entry_t* value = NULL; + + LOCK(cache); + + slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots]; + + 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; + + cache->header->num_hits++; + value = (*slot)->value; + UNLOCK(cache); + return (apc_cache_entry_t*)value; + } + slot = &(*slot)->next; + } + + UNLOCK(cache); + return NULL; +} +/* }}} */ + +/* {{{ apc_cache_user_delete */ +int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen) +{ + 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; +} +/* }}} */ + +/* {{{ apc_cache_release */ +void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry) +{ + /* local cache refcount-- is done in apc_local_cache_cleanup */ + if(entry->local) return; + + LOCK(cache); + entry->ref_count--; + UNLOCK(cache); +} +/* }}} */ + +/* {{{ 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) +{ + 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; + } + + 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; + } + 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; + } + } + + 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); +#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; + } + key->type = APC_CACHE_KEY_FILE; + return 1; +} +/* }}} */ + +/* {{{ apc_cache_make_user_key */ +int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t) +{ + assert(key != NULL); + + if (!identifier) + return 0; + + key->data.user.identifier = identifier; + key->data.user.identifier_len = identifier_len; + key->mtime = t; + key->type = APC_CACHE_KEY_USER; + return 1; +} +/* }}} */ + +/* {{{ apc_cache_make_file_entry */ +apc_cache_entry_t* apc_cache_make_file_entry(const char* filename, + zend_op_array* op_array, + apc_function_t* functions, + apc_class_t* classes) +{ + apc_cache_entry_t* entry; + + 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; +} +/* }}} */ + +/* {{{ 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(); + + 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); + + if(APCG(copied_zvals)) { + zend_hash_destroy(APCG(copied_zvals)); + efree(APCG(copied_zvals)); + } + + APCG(copied_zvals) = old; + + return dst; + } +} +/* }}} */ + +/* {{{ apc_cache_fetch_zval */ +zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate) +{ + 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); + + if(APCG(copied_zvals)) { + zend_hash_destroy(APCG(copied_zvals)); + efree(APCG(copied_zvals)); + } + + APCG(copied_zvals) = old; + + return dst; + } +} +/* }}} */ + +/* {{{ 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)); + } + + APCG(copied_zvals) = old; + } +} +/* }}} */ + +/* {{{ 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) +{ + apc_cache_entry_t* entry; + + entry = (apc_cache_entry_t*) apc_sma_malloc(sizeof(apc_cache_entry_t)); + if (!entry) 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; + } + apc_sma_free(entry); + } +} +/* }}} */ + +/* {{{ apc_cache_info */ +apc_cache_info_t* apc_cache_info(apc_cache_t* cache, zend_bool limited) +{ + 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_cache_free_info */ +void apc_cache_free_info(apc_cache_info_t* info) +{ + 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); + } + 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); + } + 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) +{ + return cache->header->busy; +} +/* }}} */ + +#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); +} +/* }}} */ + +/* {{{ apc_cache_write_unlock */ +void apc_cache_write_unlock(apc_cache_t* cache) +{ + apc_lck_unlock(cache->header->wrlock); +} +/* }}} */ +#endif + +/* {{{ 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; + + value = apc_emalloc(sizeof(apc_cache_entry_t)); + memcpy(value, slot->value, sizeof(apc_cache_entry_t)); /* bitwise copy */ + value->local = 1; + + lslot->original = slot; + lslot->value = value; + lslot->num_hits++; + + return lslot; /* for what joy ? ... consistency */ +} +/* }}} */ + +/* {{{ free_local_slot */ +static void free_local_slot(apc_local_cache_t* cache, local_slot_t* lslot) +{ + 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 */ + + lslot->original = NULL; + lslot->value = NULL; + + dead->next = cache->dead_list; + cache->dead_list = dead; +} +/* }}} */ + +/* {{{ apc_local_cache_create */ +apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl) +{ + apc_local_cache_t* cache = NULL; + + cache = (apc_local_cache_t*) apc_emalloc(sizeof(apc_local_cache_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->shmcache = shmcache; + cache->num_slots = num_slots; + cache->ttl = ttl; + cache->num_hits = 0; + cache->generation = shmcache->header->expunges; + cache->dead_list = NULL; + + 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_local_cache_destroy */ +void apc_local_cache_destroy(apc_local_cache_t* cache) +{ + int i; + for(i = 0; i < cache->num_slots; i++) { + free_local_slot(cache, &cache->slots[i]); + } + + apc_local_cache_cleanup(cache); + + LOCK(cache->shmcache); + cache->shmcache->header->num_hits += cache->num_hits; + UNLOCK(cache->shmcache); + + apc_efree(cache->slots); + apc_efree(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) +{ + slot_t* slot; + local_slot_t* lslot; + + 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]; + + slot = lslot->original; + + if(slot && key.type == slot->key.type) { + if(slot->access_time < (t - cache->ttl)) { + goto not_found; + } + 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; + } + } + } +not_found: + if(apc_cache_busy(cache->shmcache)) { + return NULL; + } + + slot = apc_cache_find_slot(cache->shmcache, key, t); + + 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; + } + 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. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: apc_cache.h,v 3.45 2007/03/22 16:03:59 gopalv Exp $ */ + +#ifndef APC_CACHE_H +#define APC_CACHE_H + +/* + * This module defines the shared memory file cache. Basically all of the + * logic for storing and retrieving cache entries lives here. + */ + +#include "apc.h" +#include "apc_compile.h" + +#define APC_CACHE_ENTRY_FILE 1 +#define APC_CACHE_ENTRY_USER 2 + +#define APC_CACHE_KEY_FILE 1 +#define APC_CACHE_KEY_USER 2 +#define APC_CACHE_KEY_FPFILE 3 + +/* {{{ struct definition: apc_cache_key_t */ +#define T apc_cache_t* +typedef struct apc_cache_t apc_cache_t; /* opaque cache type */ + +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; + +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; +}; +/* }}} */ + +/* {{{ 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_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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +/* 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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +/* {{{ 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; +/* }}} */ + +/* {{{ 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; +}; +/* }}} */ + +/* {{{ 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; +}; +/* }}} */ + +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. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: apc_compile.c,v 3.85 2007/03/28 07:35:55 gopalv Exp $ */ + +#include "apc_compile.h" +#include "apc_globals.h" +#include "apc_zend.h" + +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); + +#ifdef ZEND_ENGINE_2 +typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*); +#endif + +#define CHECK(p) { if ((p) == NULL) return NULL; } + +/* {{{ internal function declarations */ + +static int is_derived_class(zend_op_array* op_array, const char* key, int key_size); + +static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_malloc_t); + +/* + * 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 + +/* + * 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 + +/* + * 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 + +#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 + +#endif + +/* + * 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 + +/* }}} */ + +/* {{{ check_op_array_integrity */ +#if 0 +static void check_op_array_integrity(zend_op_array* src) +{ + int i, j; + + /* 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! */ + + assert(src->refcount != NULL); + assert(src->opcodes != NULL); + assert(src->last > 0); + + 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); + + 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 +/* }}} */ + +/* {{{ is_derived_class */ +static int is_derived_class(zend_op_array* op_array, const char* key, int key_size) +{ + int i; + + /* + * 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. + */ + + 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)) + { + return 1; + } + } + } + + return 0; +} +/* }}} */ + +/* {{{ my_bitwise_copy_function */ +static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate) +{ + assert(src != NULL); + + if (!dst) { + CHECK(dst = (zend_function*) allocate(sizeof(src[0]))); + } + + /* 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_malloc_t allocate, apc_free_t deallocate) +{ + int local_dst_alloc = 0; + zval* dst_new; + + assert(src != NULL); + + if (!dst) { + CHECK(dst = (zval**) allocate(sizeof(zval*))); + local_dst_alloc = 1; + } + + if(!(dst[0] = (zval*) allocate(sizeof(zval)))) { + if(local_dst_alloc) deallocate(dst); + return NULL; + } + dst_new = my_copy_zval(*dst, *src, allocate, deallocate); + if(dst_new != *dst) { + deallocate(*dst); + *dst = dst_new; + } + + (*dst)->refcount = (*src)->refcount; + (*dst)->is_ref = (*src)->is_ref; + + return dst; +} +/* }}} */ + +/* {{{ my_copy_zval */ +static zval* my_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate) +{ + 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; + + 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(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: + + 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; + + 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; + + default: + assert(0); + } + + return dst; +} +/* }}} */ + +/* {{{ my_copy_znode */ +static znode* my_copy_znode(znode* dst, znode* src, apc_malloc_t allocate, apc_free_t deallocate) +{ + 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) { + if(!my_copy_zval(&dst->u.constant, &src->u.constant, allocate, deallocate)) { + return NULL; + } + } + + 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) +{ + assert(dst != NULL); + assert(src != NULL); + + memcpy(dst, src, sizeof(src[0])); + + 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) + { + return NULL; + } + + return dst; +} +/* }}} */ + +/* {{{ my_copy_function */ +static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate) +{ + int local_dst_alloc = 0; + TSRMLS_FETCH(); + + assert(src != NULL); + + if(!dst) local_dst_alloc = 1; + CHECK(dst = my_bitwise_copy_function(dst, src, allocate)); + + 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; + + 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. + */ + + /* 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; + + /* 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 + + + return dst; +} +/* }}} */ + +/* {{{ 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) +{ + int local_dst_alloc = 0; + assert(src != NULL); + + if (!dst) { + CHECK(dst = (zend_function_entry*) allocate(sizeof(src[0]))); + local_dst_alloc = 1; + } + + /* Start with a bitwise copy */ + memcpy(dst, src, sizeof(src[0])); + + dst->fname = NULL; +#ifdef ZEND_ENGINE_2 + dst->arg_info = NULL; +#else + dst->func_arg_types = NULL; +#endif + + if (src->fname) { + if(!(dst->fname = apc_xstrdup(src->fname, allocate))) { + goto cleanup; + } + } + +#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; + } + } +#endif + + return dst; + +cleanup: + if(dst->fname) deallocate(dst->fname); + if(local_dst_alloc) deallocate(dst); + return NULL; +} +/* }}} */ + +#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; + + assert(src != NULL); + + if (!dst) { + CHECK(dst = (zend_property_info*) allocate(sizeof(*src))); + local_dst_alloc = 1; + } + + /* Start with a bitwise copy */ + memcpy(dst, src, sizeof(*src)); + + 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 + */ + if(!(dst->name = + apc_xmemcpy(src->name, src->name_length+1, allocate))) { + goto cleanup; + } + } + +#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; + } + } +#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; +} +/* }}} */ + +/* {{{ 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) +{ + 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; +} +/* }}} */ + +/* {{{ 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) +{ + int local_dst_alloc = 0; + int i = 0; + + + if (!dst) { + CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)*num_args)); + local_dst_alloc = 1; + } + + /* 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; + } + } + + return dst; +} +/* }}} */ + +/* {{{ 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) +{ + int local_dst_alloc = 0; + + assert(src != NULL); + + if (!dst) { + CHECK(dst = (zend_arg_info*) allocate(sizeof(*src))); + local_dst_alloc = 1; + } + + /* Start with a bitwise copy */ + memcpy(dst, src, sizeof(*src)); + + dst->name = NULL; + dst->class_name = NULL; + + if (src->name) { + if(!(dst->name = + apc_xmemcpy(src->name, src->name_len+1, allocate))) { + goto cleanup; + } + } + + if (src->class_name) { + if(!(dst->class_name = + apc_xmemcpy(src->class_name, src->class_name_len+1, allocate))) { + goto cleanup; + } + } + + return dst; + +cleanup: + if(dst->name) deallocate(dst->name); + if(dst->class_name) deallocate(dst->name); + if(local_dst_alloc) deallocate(dst); + return NULL; +} +/* }}} */ +#endif + +/* {{{ 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; + + assert(src != NULL); + + if (!dst) { + CHECK(dst = (zend_class_entry*) allocate(sizeof(*src))); + local_dst_alloc = 1; + } + + /* Start with a bitwise copy */ + memcpy(dst, src, sizeof(*src)); + + 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; +#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)); +#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; +#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 + + 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; + } + +#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; + } + +#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; + } + + 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; + } + } +#endif + + if (src->builtin_functions) { + int i, n; + + for (n = 0; src->type == ZEND_INTERNAL_CLASS && src->builtin_functions[n].fname != NULL; n++) {} + + if(!(dst->builtin_functions = + (zend_function_entry*) + allocate((n + 1) * sizeof(zend_function_entry)))) { + goto cleanup; + } + + + for (i = 0; i < n; i++) { + if(!my_copy_function_entry(&dst->builtin_functions[i], + &src->builtin_functions[i], + allocate, deallocate)) { + int ii; + + for(ii=i-1; i>=0; i--) my_destroy_function_entry(&dst->builtin_functions[ii], deallocate); + goto cleanup; + } + } + dst->builtin_functions[n].fname = NULL; + } + +#ifdef ZEND_ENGINE_2 + if (src->filename) { + if(!(dst->filename = apc_xstrdup(src->filename, allocate))) { + goto cleanup; + } + } +#endif + + return dst; + + +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); + +#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); + + return NULL; +} +/* }}} */ + +/* {{{ 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; + + assert(src != NULL); + + if (!dst) { + CHECK(dst = (HashTable*) allocate(sizeof(src[0]))); + local_dst_alloc = 1; + } + + memcpy(dst, src, sizeof(src[0])); + + /* allocate buckets for the new hashtable */ + if(!(dst->arBuckets = allocate(dst->nTableSize * sizeof(Bucket*)))) { + if(local_dst_alloc) deallocate(dst); + return NULL; + } + + 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; + + 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; + } + + va_end(args); + } + + /* create a copy of the bucket 'curr' */ + if(!(newp = + (Bucket*) apc_xmemcpy(curr, + sizeof(Bucket) + curr->nKeyLength - 1, + allocate))) { + goto cleanup; + } + + /* 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; + } + + dst->arBuckets[n] = newp; + + /* copy the bucket data using our 'copy_fn' callback function */ + if(!(newp->pData = copy_fn(NULL, curr->pData, allocate, deallocate))) { + goto cleanup; + } + + 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; + } + + dst->pListTail = newp; + + 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; + + return NULL; +} +/* }}} */ + +/* {{{ 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; + } + + 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); + + if (!dst) { + CHECK(dst = (zval*) allocate(sizeof(zval))); + local_dst_alloc = 1; + } + + dst = my_copy_zval(dst, src, allocate, deallocate); + if(!dst) { + if(local_dst_alloc) deallocate(dst); + return NULL; + } + return dst; +} +/* }}} */ + +#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; + + 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; + } + } +} +/* }}} */ +#endif + +/* {{{ 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; +#endif + + assert(src != NULL); + + 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); + } + + /* 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 + + /* 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; + } + } +#endif + + 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; + } + } + + if(!(dst->refcount = apc_xmemcpy(src->refcount, + sizeof(src->refcount[0]), + allocate))) { + goto cleanup; + } + + /* deep-copy the opcodes */ + if(!(dst->opcodes = (zend_op*) allocate(sizeof(zend_op) * src->last))) { + goto cleanup; + } + +#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); + } + } + } + } + } +#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; + } + } + + /* copy the table of static variables */ + if (src->static_variables) { + if(!(dst->static_variables = my_copy_static_variables(src, allocate, deallocate))) { + goto cleanup_opcodes; + } + } + +#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; + } + } +#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; + } + } + } +#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; + } + } +#endif + + return dst; + +cleanup_opcodes: + if(dst->opcodes) { + for(i=0; i < src->last; i++) my_destroy_zend_op(dst->opcodes+i, deallocate); + } +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); + } +#endif + if(local_dst_alloc) deallocate(dst); + return NULL; +} +/* }}} */ + +/* {{{ apc_copy_new_functions */ +apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate 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))); + + if (new_count == 0) { + array[0].function = NULL; + return array; + } + + /* 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)); + } + + array[i].function = NULL; + return array; +} +/* }}} */ + +/* {{{ 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)); + } + + /* 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; + + 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; + } + + /* + * 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. + */ + + 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; + } + array[i].is_derived = 1; + } + else { + array[i].parent_name = NULL; + array[i].is_derived = is_derived_class(op_array, key, key_size); + } + + zend_hash_move_forward(CG(class_table)); + } + + 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]); + } +} +/* }}} */ + +/* {{{ my_destroy_zval */ +static int my_destroy_zval(zval* src, apc_free_t deallocate) +{ + zval **tmp; + TSRMLS_FETCH(); + + switch (src->type & ~IS_CONSTANT_INDEX) { + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + case IS_DOUBLE: + case IS_NULL: + break; + + 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); + } + /* fall through */ + + case IS_CONSTANT_ARRAY: + my_free_hashtable(src->value.ht, + (ht_free_fun_t) my_free_zval_ptr, + deallocate); + break; + + 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 + break; + + default: + assert(0); + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ my_destroy_znode */ +static void my_destroy_znode(znode* src, apc_free_t deallocate) +{ + if (src->op_type == IS_CONST) { + my_destroy_zval(&src->u.constant, deallocate); + } +} +/* }}} */ + +/* {{{ my_destroy_zend_op */ +static void my_destroy_zend_op(zend_op* src, apc_free_t deallocate) +{ + my_destroy_znode(&src->result, deallocate); + my_destroy_znode(&src->op1, deallocate); + my_destroy_znode(&src->op2, deallocate); +} +/* }}} */ + +/* {{{ my_destroy_function */ +static void my_destroy_function(zend_function* src, apc_free_t deallocate) +{ + assert(src != NULL); + + switch (src->type) { + case ZEND_INTERNAL_FUNCTION: + case ZEND_OVERLOADED_FUNCTION: + break; + + case ZEND_USER_FUNCTION: + case ZEND_EVAL_CODE: + my_destroy_op_array(&src->op_array, deallocate); + break; + + default: + assert(0); + } +} +/* }}} */ + +/* {{{ my_destroy_function_entry */ +static void my_destroy_function_entry(zend_function_entry* src, apc_free_t deallocate) +{ + assert(src != 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 +} +/* }}} */ + +#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 +} +/* }}} */ + +/* {{{ my_destroy_arg_info_array */ +static void my_destroy_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate) +{ + int i = 0; + + assert(src != NULL); + + for(i=0; i < num_args; i++) { + my_destroy_arg_info(&src[i], deallocate); + } +} +/* }}} */ + +/* {{{ my_destroy_arg_info */ +static void my_destroy_arg_info(zend_arg_info* src, apc_free_t deallocate) +{ + assert(src != NULL); + + deallocate(src->name); + deallocate(src->class_name); +} +/* }}} */ +#endif + +/* {{{ my_destroy_class_entry */ +static void my_destroy_class_entry(zend_class_entry* src, apc_free_t deallocate) +{ + uint i; + + 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); + + my_destroy_hashtable(&src->default_properties, + (ht_free_fun_t) my_free_zval_ptr, + deallocate); + +#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); + } + } + + my_destroy_hashtable(&src->constants_table, + (ht_free_fun_t) my_free_zval_ptr, + deallocate); +#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); + } +} +/* }}} */ + +/* {{{ my_destroy_hashtable */ +static void my_destroy_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate) +{ + 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); + } + } + + deallocate(src->arBuckets); +} +/* }}} */ + +/* {{{ my_destroy_op_array */ +static void my_destroy_op_array(zend_op_array* src, apc_free_t deallocate) +{ + int i; + + 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); + } +#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); + + if (src->brk_cont_array) { + deallocate(src->brk_cont_array); + } + + 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 +} +/* }}} */ + +/* {{{ my_free_zval_ptr */ +static void my_free_zval_ptr(zval** src, apc_free_t deallocate) +{ + my_destroy_zval_ptr(src, deallocate); + deallocate(src); +} +/* }}} */ + +#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); +} +/* }}} */ + +/* {{{ 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); +} +/* }}} */ + +/* {{{ 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 + +/* {{{ my_free_function */ +static void my_free_function(zend_function* src, apc_free_t deallocate) +{ + my_destroy_function(src, deallocate); + deallocate(src); +} +/* }}} */ + +/* {{{ 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); +} +/* }}} */ + +/* {{{ 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); + } +} +/* }}} */ + +/* {{{ apc_free_functions */ +void apc_free_functions(apc_function_t* src, apc_free_t deallocate) +{ + 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); + } +} +/* }}} */ + +/* {{{ apc_free_classes */ +void apc_free_classes(apc_class_t* src, apc_free_t deallocate) +{ + int i; + + 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); + } +} +/* }}} */ + +/* {{{ 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); + } + } +} +/* }}} */ + + +/* 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); \ + } \ + +/* {{{ 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); + +#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); + +#else + int needcopy = 0; + int do_prepare_fetch_global = 0; + int j = 0; + + 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; + } + } +#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) { + + 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(!(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; + } +#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) { + + 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(); + } + + i--; + zo++; + } + } +#endif + } + return 1; +} +/* }}} */ + +/* {{{ 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])); + } + memcpy(dst, src, sizeof(src[0])); + dst->static_variables = my_copy_static_variables(src, apc_php_malloc, apc_php_free); + + dst->refcount = apc_xmemcpy(src->refcount, + sizeof(src->refcount[0]), + apc_php_malloc); + + my_prepare_op_array_for_execution(dst,src TSRMLS_CC); + + return dst; +} +/* }}} */ + +/* {{{ apc_copy_function_for_execution */ +zend_function* apc_copy_function_for_execution(zend_function* src) +{ + zend_function* dst; + TSRMLS_FETCH(); + + 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) +{ + if(src->type==ZEND_INTERNAL_FUNCTION || src->type==ZEND_OVERLOADED_FUNCTION) return src; + return apc_copy_function_for_execution(src); +} +/* }}} */ + +/* {{{ 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])); + +#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); */ + } +#endif + +#ifndef ZEND_ENGINE_2 + dst->refcount = apc_xmemcpy(src->refcount, + sizeof(src->refcount[0]), + apc_php_malloc); +#endif + + /* Deep-copy the class properties, because they will be modified */ + + 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); + + /* For derived classes, we must also copy the function hashtable (although + * we can merely bitwise copy the functions it contains) */ + + 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); + + /* 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); + +#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 inheritance results in a hash_del, it might result in + * a pefree() of the pointers here. Deep copying required. + */ + + 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); + + 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); + + 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); + } + +#endif + + return dst; +} +/* }}} */ + +/* {{{ apc_free_class_entry_after_execution */ +void apc_free_class_entry_after_execution(zend_class_entry* src) +{ +#ifdef ZEND_ENGINE_2 + if(src->num_interfaces > 0 && src->interfaces) { + apc_php_free(src->interfaces); + src->interfaces = NULL; + src->num_interfaces = 0; + } + /* 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; + } + zend_hash_clean(&src->default_properties); + zend_hash_clean(&src->constants_table); +#endif + + /* TODO: more cleanup */ +} +/* }}} */ + +#ifdef ZEND_ENGINE_2 + +/* {{{ 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) + + 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); +#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 */ + } +} +/* }}} */ +#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; + } + } +} +/* }}} */ + +#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; +#endif + +#ifdef ZEND_ENGINE_2 + return (zf->common.scope == src); +#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; + } + } + return 1; +#endif +} +/* }}} */ + +/* {{{ 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; + + if (parent && + zend_hash_quick_find(&parent->default_properties, p->arKey, + p->nKeyLength, p->h, (void **) &parent_prop)==SUCCESS) { + + if((parent_prop && child_prop) && (*parent_prop) == (*child_prop)) + { + return 0; + } + } + + /* possibly not in the parent */ + return 1; +} +/* }}} */ + +#ifdef ZEND_ENGINE_2 + +/* {{{ 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; +} +/* }}} */ + +/* {{{ 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(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; + } + } + } + + 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 | + +----------------------------------------------------------------------+ + + 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_compile.h,v 3.19 2007/03/08 22:03:35 gopalv Exp $ */ + +#ifndef APC_COMPILE_H +#define APC_COMPILE_H + +/* + * 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. + */ + +#include "apc.h" +#include "apc_php.h" + +/* {{{ 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 */ +}; +/* }}} */ + +/* {{{ 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 */ +}; +/* }}} */ + +/* {{{ 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 */ + + /* 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; +}; +/* }}} */ + +/* + * These are the top-level copy functions. + */ + +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); + +/* + * Deallocation functions corresponding to the copy functions above. + */ + +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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +#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_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 | + +----------------------------------------------------------------------+ + + 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_debug.c,v 3.6 2006/12/07 23:51:28 gopalv Exp $ */ +#include "apc.h" +#include +#include "zend_compile.h" + +#ifdef __DEBUG_APC__ + +#include + +/* keep track of vld_dump_oparray() signature */ +typedef void (*vld_dump_f) (zend_op_array * TSRMLS_DC); + +#endif + +void dump(zend_op_array *op_array TSRMLS_DC) +{ +#ifdef __DEBUG_APC__ + vld_dump_f dump_op_array = dlsym(NULL, "vld_dump_oparray"); + + 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 + +SOURCE=.\apc_php.h +# End Source File +# Begin Source File + +SOURCE=.\apc_shm.h +# End Source File +# Begin Source File + +SOURCE=.\apc_sma.h +# End Source File +# Begin Source File + +SOURCE=.\apc_stack.h +# End Source File +# Begin Source File + +SOURCE=.\apc_zend.h +# End Source File +# Begin Source File + +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 | + +----------------------------------------------------------------------+ + + 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_fcntl.c,v 3.25 2006/06/19 02:52:49 rasmus Exp $ */ + +#include "apc_fcntl.h" +#include "apc.h" +#include +#include + +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; + } + } + 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:"); + } +} + +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:"); + } +} + +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; +} + +void apc_fcntl_unlock(int fd) +{ + 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 | + +----------------------------------------------------------------------+ + + 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_fcntl.h,v 3.14 2006/05/31 22:24:48 rasmus Exp $ */ + +#ifndef APC_FCNTL_H +#define APC_FCNTL_H + + +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); +#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. + + */ + +/* $Id: apc_fcntl_win32.c,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */ + +#include "apc_fcntl.h" +#include "apc.h" +#include +#include +#include +#include +#include +#include + +int apc_fcntl_create(const char* pathname) +{ + 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; + } + + 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); + + + 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; +} + +void apc_fcntl_destroy(int fd) +{ + CloseHandle((HANDLE)fd); +} + +void apc_fcntl_lock(int fd) +{ + 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()); + } +} + +void apc_fcntl_rdlock(int fd) +{ + 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()); + } +} + +void apc_fcntl_unlock(int fd) +{ + OVERLAPPED offset = {0, 0, 0, 0, NULL}; + + 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); + } + } +} + +/* + * 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 | + +----------------------------------------------------------------------+ + + */ + +/* $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 +* +***************************************************************************/ + +#include "apc.h" +#include "apc_futex.h" + +#ifdef APC_FUTEX_LOCKS + + +inline int apc_futex_create() +{ + return 0; +} + +inline void apc_futex_destroy(volatile int* lock) +{ + return; +} + +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); + } + } + +} + +/* 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; +} + + +inline void apc_futex_unlock(volatile int* lock) +{ + /* 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); + } +} + +#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_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 | + +----------------------------------------------------------------------+ + + */ + +/* $Id: apc_futex.h,v 3.2 2006/10/12 08:23:16 shire Exp $ */ + +#ifndef APC_FUTEX_H +#define APC_FUTEX_H + +#include "apc.h" + +#ifdef APC_FUTEX_LOCKS + +#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) + +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); + +#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 + */ 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 | + +----------------------------------------------------------------------+ + + 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_globals.h,v 3.59 2007/03/21 21:07:28 rasmus Exp $ */ + +#ifndef APC_GLOBALS_H +#define APC_GLOBALS_H + +#define APC_VERSION "3.0.14" + +#include "apc_cache.h" +#include "apc_stack.h" +#include "apc_php.h" + +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 */ + + /* 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) + +/* (the following declaration is defined in php_apc.c) */ +ZEND_EXTERN_MODULE_GLOBALS(apc) + +#ifdef ZTS +# define APCG(v) TSRMG(apc_globals_id, zend_apc_globals *, v) +#else +# define APCG(v) (apc_globals.v) +#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 */ + +#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.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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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.h,v 3.14 2007/03/17 14:01:41 gopalv Exp $ */ + +#ifndef APC_H +#define APC_H + +/* + * This module defines utilities and helper functions used elsewhere in APC. + */ + +/* 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 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "php.h" + +/* log levels constants (see apc_log) */ +enum { APC_DBG, APC_NOTICE, APC_WARNING, APC_ERROR }; + +/* typedefs for extensible memory allocators */ +typedef void* (*apc_malloc_t)(size_t); +typedef void (*apc_free_t) (void*); + +/* 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); + +/* 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, ...); + +/* 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); + +/* filesystem functions */ + +typedef struct apc_fileinfo_t +{ + char fullpath[MAXPATHLEN+1]; + struct stat st_buf; +} apc_fileinfo_t; + +#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); + +/* 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); + +/* apc_crc32: returns the CRC-32 checksum of the first len bytes in buf */ +extern unsigned int apc_crc32(const char* buf, int len); + +#define APC_NEGATIVE_MATCH 1 +#define APC_POSITIVE_MATCH 2 + +#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_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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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_lock.h,v 3.20 2007/01/29 07:39:02 shire Exp $ */ + +#ifndef APC_LOCK +#define APC_LOCK + +#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 +#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)) +#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) +#endif + +#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 @@ +/* + +----------------------------------------------------------------------+ + | 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. + + 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 */ + +/* 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; + +/* }}} */ + +/* {{{ 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 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); + + if (status == FAILURE) { + /* apc_eprint("Cannot redeclare %s()", fn.name); */ + } + + return status; +} +/* }}} */ + +/* {{{ install_class */ +static int install_class(apc_class_t cl 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; + } + } + +#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; + } + + *allocated_ce = +#endif + class_entry = + apc_copy_class_entry_for_execution(cl.class_entry, + cl.is_derived); + + + /* 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 + } + + + } + +#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) +{ + 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; +} +/* }}} */ + +/* {{{ compare_file_handles */ +static int compare_file_handles(void* a, void* b) +{ + 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); +} +/* }}} */ + +/* {{{ cached_compile */ +static zend_op_array* cached_compile(zend_file_handle* h, + int type 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) { + 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; + } + } + } + + 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); + } + } + + + return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array TSRMLS_CC); + +default_compile: + + cache_entry->autofiltered = 1; + if(APCG(report_autofilter)) { + apc_wprint("Autofiltering %s", h->opened_path); + } + + 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); +} +/* }}} */ + +/* {{{ 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; + + if (!APCG(enabled) || (apc_cache_busy(apc_cache) && !APCG(localcache))) { + return old_compile_file(h, type TSRMLS_CC); + } + + /* 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); + } + +#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 + + /* 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(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); + } + + 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); + } + + 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; + } + } + + HANDLE_BLOCK_INTERRUPTIONS(); + +#if NONBLOCKING_LOCK_AVAILABLE + if(APCG(write_lock)) { + if(!apc_cache_write_lock(apc_cache)) { + HANDLE_UNBLOCK_INTERRUPTIONS(); + return op_array; + } + } +#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; + } + + path = h->opened_path; + if(!path) path=h->filename; + +#ifdef __DEBUG_APC__ + fprintf(stderr,"2. h->opened_path=[%s] h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename); +#endif + + 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; + } + 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); + } + } + +#if NONBLOCKING_LOCK_AVAILABLE + if(APCG(write_lock)) { + apc_cache_write_unlock(apc_cache); + } +#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + + return op_array; +} +/* }}} */ + +/* {{{ 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)*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); + + 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); + } + + apc_cache_destroy(apc_cache); + apc_cache_destroy(apc_user_cache); + apc_sma_cleanup(); + + APCG(initialized) = 0; + return 0; +} + +/* }}} */ + +/* {{{ 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; +} + +int apc_process_shutdown(TSRMLS_D) +{ + if(APCG(initialized) && APCG(localcache) && APCG(lcache)) { + apc_local_cache_destroy(APCG(lcache)); + APCG(lcache) = NULL; + } + return 0; +} +/* }}} */ + +/* {{{ 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; +} + +/* }}} */ + +/* {{{ 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; +#endif + + 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++) { +#ifdef ZEND_ENGINE_2 + centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */ +#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; +#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 + */ 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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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,v 3.9 2007/02/28 01:15:18 gopalv Exp $ */ + +#ifndef APC_MAIN_H +#define APC_MAIN_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); + +/* + * 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(); + + +extern const char* apc_version(); + +#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_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 @@ +/* + +----------------------------------------------------------------------+ + | 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: 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,v 3.5 2006/03/12 00:31:45 rasmus Exp $ */ + +#include "apc.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 + +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); + } else { + int fd; + + /* + * 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); + } + /* + * 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; + } + 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:"); + } + 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:"); + } + return shmaddr; +} + +void apc_unmap(void* shmaddr, int size) +{ + munmap(shmaddr, 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 + */ 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 | + +----------------------------------------------------------------------+ + + All other licensing and usage conditions are those of the PHP Group. + + */ + +$VERSION='$Id: apc.php,v 3.65 2006/10/27 18:32:52 shire Exp $'; + +////////// 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 + +////////// 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'],'')) : ''; +$time = time(); +$host = getenv('HOSTNAME'); +if($host) { $host = '('.$host.')'; } + +// 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 + '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' => '/^.*$/' // 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,$_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(!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]; + 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; + + // 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; +} + +// 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; + } +} + + +?> + + +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) : $value,"
    Stored Value
    ";
    +					$output = var_export(apc_fetch($entry[$fieldkey]),true);
    +					echo htmlspecialchars($output);
    +					echo "
    +
    +EOB; + break; + } + + $cols=6; + echo <<
    Scope: + + ", + ", Sorting:', + '', + '', + '  Search: ', + ' ', + '
    ', + + '
    ', + '', + '', + '', + '', + '', + '', + ''; + + 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'].'/i', $entry[$fieldname]) != 0) { + echo + '', + "', + '', + '', + '', + '', + ''; + + if($fieldname=='info') { + if($entry['ttl']) + 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']),'
    ",$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...'; + } + + 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; + + $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; + } + echo "".htmlspecialchars($v)."
    "; + echo nl2br(htmlspecialchars(current($match[2])))."
    "; + next($match[2]); + } + echo '
    + +EOB; + break; + +} + +echo <<< EOB + +EOB; + +?> + + + + 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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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,v 3.10 2006/11/16 20:24:48 gopalv Exp $ */ + +#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 > 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 + +#include "rfc1867.h" + +#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_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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + */ + +/* $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)); + + 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."); + } + + /* 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."); + } + + if(pthread_mutex_init(lock, attr)) { + apc_eprint("unable to initialize pthread lock"); + } + 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) +{ + 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)"); + } +} + +void apc_pthreadmutex_unlock(pthread_mutex_t *lock) +{ + if(pthread_mutex_unlock(lock)) { + apc_eprint("unable to unlock pthread lock"); + } +} + +zend_bool apc_pthreadmutex_nonblocking_lock(pthread_mutex_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; + } +} + + +#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_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 @@ -0,0 +1,48 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + */ + +/* $Id: apc_pthreadmutex.h,v 3.3 2007/01/28 07:53:57 shire Exp $ */ + +#ifndef APC_PTHREADMUTEX_H +#define APC_PTHREADMUTEX_H + +#include "apc.h" + +#ifdef APC_PTHREADMUTEX_LOCKS + +#include + +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); + +#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 + */ 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 @@ +/* + +----------------------------------------------------------------------+ + | 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: 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,v 3.4 2007/02/24 11:45:29 rasmus Exp $*/ + +#include "apc.h" +#include "rfc1867.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); + +static double my_time() { + struct timeval a; + double t; + gettimeofday(&a, NULL); + t = a.tv_sec + (a.tv_usec/1000000); + return t; +} + +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; + + 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; + + case MULTIPART_EVENT_FORMDATA: + { + multipart_event_formdata *data = (multipart_event_formdata *) event_data; + + 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; + + case MULTIPART_EVENT_FILE_START: + if(*tracking_key) { + multipart_event_file_start *data = (multipart_event_file_start *) event_data; + + 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; + + 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; + + 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; + + 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; + } +} + +#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_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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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,v 3.16 2006/03/12 00:31:45 rasmus Exp $ */ + +#include "apc_sem.h" +#include "apc.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(const char* pathname, int proj, int initval) +{ + int semid; + int perms; + union semun arg; + key_t key; + + perms = 0777; + + key = IPC_PRIVATE; + if (pathname != NULL) { + if ((key = ftok(pathname, proj)) < 0) { + apc_eprint("apc_sem_create: ftok(%s,%d) failed:", pathname, proj); + } + } + + 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); + } + } + 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 */ + } + else { + apc_eprint("apc_sem_create: semget(%u,...) failed:", 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) +{ + 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_eprint("apc_sem_lock: semop(%d) failed:", semid); + } + } +} + +void apc_sem_unlock(int semid) +{ + 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_eprint("apc_sem_unlock: semop(%d) failed:", semid); + } + } +} + +void apc_sem_wait_for_zero(int semid) +{ + 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_eprint("apc_sem_waitforzero: semop(%d) failed:", semid); + } + } +} + +int apc_sem_get_value(int semid) +{ + union semun arg; + unsigned short val[1]; + + arg.array = val; + if (semctl(semid, 0, GETALL, arg) < 0) { + apc_eprint("apc_sem_getvalue: semctl(%d,...) failed:", semid); + } + return val[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_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 @@ -0,0 +1,51 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */ + +#ifndef APC_SEM_H +#define APC_SEM_H + +/* Wrapper functions for SysV sempahores */ + +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); + +#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_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 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | + | Rasmus Lerdorf | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. + Future revisions and derivatives of this source code must acknowledge + Community Connect Inc. as the original contributor of this module by + leaving this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: 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 + +#ifndef SHM_R +# define SHM_R 0444 /* read permission */ +#endif +#ifndef SHM_A +# define SHM_A 0222 /* write permission */ +#endif + +int apc_shm_create(const char* pathname, int proj, int size) +{ + 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:"); + } + } +#endif + + 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)); + } + + 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); +} + +void* apc_shm_attach(int shmid) +{ + void* shmaddr; /* the shared memory address */ + + if ((int)(shmaddr = shmat(shmid, 0, 0)) == -1) { + apc_eprint("apc_shm_attach: shmat failed:"); + } + + /* + * 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_shm_detach(void* shmaddr) +{ + if (shmdt(shmaddr) < 0) { + apc_eprint("apc_shm_detach: shmdt 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_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 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */ + +#ifndef APC_SHM_H +#define APC_SHM_H + +/* Wrapper functions for unix shared memory */ + +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); + +#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_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 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Daniel Cowgill | + | Rasmus Lerdorf | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. + Future revisions and derivatives of this source code must acknowledge + Community Connect Inc. as the original contributor of this module by + leaving this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: 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 + +/* {{{ 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(); } +/* }}} */ + +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 */ + +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 +}; + + +/* 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 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 +}; + +/* 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)) + +/* 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 + + +#ifdef max +#undef max +#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) +{ + 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)); + + realsize = ALIGNWORD(size + block_size); + + /* + * 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; + } + + prvnextfit = 0; /* initially null (no fit) */ + last_offset = 0; + + /* If we have a next fit offset, start searching from there */ + if(header->nfoffset) { + prv = BLOCKAT(header->nfoffset); + } else { + prv = BLOCKAT(sizeof(header_t)); + } + + 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; + } + 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 (prvnextfit == 0) { + header->nfoffset = 0; + return -1; + } + + 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; + } + 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; +#endif + } + + /* 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; +} +/* }}} */ + +/* {{{ sma_deallocate: deallocates the block at the given offset */ +static int sma_deallocate(void* shmaddr, int offset) +{ + 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; + } + + nxt = BLOCKAT(cur->next); + + 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 ? */ +#endif + RESET_CANARY(nxt); + } + header->nfoffset = 0; /* Reset the next fit search marker */ + + return size; +} +/* }}} */ + +/* {{{ apc_sma_init */ + +void apc_sma_init(int numseg, int segsize, char *mmap_file_mask) +{ + int 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 = (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; + +#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; +#endif + } +} +/* }}} */ + +/* {{{ apc_sma_cleanup */ +void apc_sma_cleanup() +{ + int i; + + assert(sma_initialized); + + 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]); +#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; + + TSRMLS_FETCH(); + assert(sma_initialized); + LOCK(((header_t*)sma_shmaddrs[sma_lastseg])->sma_lock); + + 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); + + 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); + } + + return NULL; +} +/* }}} */ + +/* {{{ apc_sma_realloc */ +void* apc_sma_realloc(void *p, size_t n) +{ + apc_sma_free(p); + return apc_sma_malloc(n); +} +/* }}} */ + +/* {{{ apc_sma_strdup */ +char* apc_sma_strdup(const char* s) +{ + void* q; + int len; + + if(!s) return NULL; + + len = strlen(s)+1; + q = apc_sma_malloc(len); + if(!q) return NULL; + memcpy(q, s, len); + return q; +} +/* }}} */ + +/* {{{ apc_sma_free */ +void apc_sma_free(void* p) +{ + int i; + size_t offset; + size_t d_size; + TSRMLS_FETCH(); + + if (p == NULL) { + return; + } + + assert(sma_initialized); + + 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); + } + + apc_eprint("apc_sma_free: could not locate address %p", p); +} +/* }}} */ + +/* {{{ 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; + } + + 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)); + + info->list = apc_emalloc(info->num_seg * sizeof(apc_sma_link_t*)); + for (i = 0; i < sma_numseg; i++) { + info->list[i] = NULL; + } + + if(limited) return info; + + /* 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]; + + /* For each block in this segment */ + while (prv->next != 0) { + block_t* cur = BLOCKAT(prv->next); +#ifdef __APC_SMA_DEBUG__ + CHECK_CANARY(cur); +#endif + + *link = apc_emalloc(sizeof(apc_sma_link_t)); + (*link)->size = cur->size; + (*link)->offset = prv->next; + (*link)->next = NULL; + link = &(*link)->next; + + prv = cur; + } + UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock); + } + + return info; +} +/* }}} */ + +/* {{{ apc_sma_free_info */ +void apc_sma_free_info(apc_sma_info_t* info) +{ + int i; + + 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); +} +/* }}} */ + +/* {{{ 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; +} +/* }}} */ + +#if ALLOC_DISTRIBUTION +size_t *apc_sma_get_alloc_distribution(void) { + header_t* header = (header_t*) sma_shmaddrs[0]; + return header->adist; +} +#endif + +#if 0 +/* {{{ apc_sma_check_integrity */ +void apc_sma_check_integrity() +{ + int i; + + /* 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; + + /* For each block in this segment */ + while (prv->next != 0) { + block_t* cur = BLOCKAT(prv->next); + avail += cur->size; + prv = cur; + } + + assert(avail == header->avail); + } +} +/* }}} */ +#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_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 | + +----------------------------------------------------------------------+ + + 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.h,v 1.16 2007/02/24 11:59:40 rasmus Exp $ */ + +#ifndef APC_SMA_H +#define APC_SMA_H + +#define ALLOC_DISTRIBUTION 0 + +#include "apc.h" + +/* Simple shared memory allocator */ + +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 + +/* {{{ 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 */ +}; +/* }}} */ + +/* {{{ 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 */ +}; +/* }}} */ + +extern apc_sma_info_t* apc_sma_info(zend_bool limited); +extern void apc_sma_free_info(apc_sma_info_t* info); + +extern int apc_sma_get_avail_mem(); +extern void apc_sma_check_integrity(); + +#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_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 | + +----------------------------------------------------------------------+ + + */ + +/* $Id: apc_spin.c,v 3.1 2007/01/29 07:39:02 shire Exp $ */ + +#include "apc_spin.h" + +#ifdef APC_SPIN_LOCKS + +slock_t *apc_slock_create(slock_t *lock) +{ + S_INIT_LOCK(lock); +} + +void apc_slock_destroy(slock_t *lock) +{ + S_LOCK_FREE(lock); +} + +void apc_slock_lock(slock_t *lock) +{ + S_LOCK(lock); +} + +void apc_slock_unlock(slock_t *lock) +{ + S_UNLOCK(lock); +} + +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 */ +} + + +#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_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 | + +----------------------------------------------------------------------+ + + */ + +/* $Id: apc_spin.h,v 3.1 2007/01/29 07:39:02 shire Exp $ */ + +#ifndef APC_SPIN_H +#define APC_SPIN_H + +#include "apc.h" + +#ifdef APC_SPIN_LOCKS + +#include "pgsql_s_lock.h" + +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); + +#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 + */ 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 | + +----------------------------------------------------------------------+ + + 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.c,v 3.4 2006/03/12 00:31:45 rasmus Exp $ */ + +#include "apc_stack.h" +#include "apc.h" + +struct apc_stack_t { + void** data; + int capacity; + int size; +}; + +apc_stack_t* apc_stack_create(int size_hint) +{ + apc_stack_t* stack = (apc_stack_t*) apc_emalloc(sizeof(apc_stack_t)); + + stack->capacity = (size_hint > 0) ? size_hint : 10; + stack->size = 0; + stack->data = (void**) apc_emalloc(sizeof(void*) * stack->capacity); + + return stack; +} + +void apc_stack_destroy(apc_stack_t* stack) +{ + if (stack != NULL) { + apc_efree(stack->data); + apc_efree(stack); + } +} + +void apc_stack_clear(apc_stack_t* stack) +{ + assert(stack != NULL); + stack->size = 0; +} + +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; +} + +void* apc_stack_pop(apc_stack_t* stack) +{ + assert(stack != NULL && stack->size > 0); + return stack->data[--stack->size]; +} + +void* apc_stack_top(apc_stack_t* stack) +{ + assert(stack != NULL && stack->size > 0); + return stack->data[stack->size-1]; +} + +void* apc_stack_get(apc_stack_t* stack, int n) +{ + assert(stack != NULL && stack->size > n); + return stack->data[n]; +} + +int apc_stack_size(apc_stack_t* stack) +{ + assert(stack != NULL); + return stack->size; +} + +/* + * 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 | + +----------------------------------------------------------------------+ + + 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,v 3.4 2006/03/12 00:31:45 rasmus Exp $ */ + +#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); +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); + +#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_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 | + +----------------------------------------------------------------------+ + + 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_zend.c,v 3.14 2007/04/02 22:57:10 rasmus Exp $ */ + +#include "apc_zend.h" +#include "apc_globals.h" + +void* apc_php_malloc(size_t n) +{ + return emalloc(n); +} + +void apc_php_free(void* p) +{ + efree(p); +} + +#ifndef ZEND_VM_KIND_CALL /* Not currently defined by any ZE version */ +# define ZEND_VM_KIND_CALL 1 +#endif + +#ifndef ZEND_VM_KIND /* Indicates PHP < 5.1 */ +# define ZEND_VM_KIND ZEND_VM_KIND_CALL +#endif + +#if defined(ZEND_ENGINE_2) && (ZEND_VM_KIND == ZEND_VM_KIND_CALL) +# define APC_OPCODE_OVERRIDE +#endif + +#ifdef APC_OPCODE_OVERRIDE + +#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]; +} + +# 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; } + +#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 + +static opcode_handler_t *apc_original_opcode_handlers; +static opcode_handler_t apc_opcode_handlers[APC_OPCODE_HANDLER_COUNT]; + +#define APC_EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset)) + +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]; + + 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; + } +} + +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 (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); + } + + 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; + } + + 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); + } + + 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; + } + + if (inc_filename == &tmp_inc_filename) { + zval_dtor(&tmp_inc_filename); + } + + 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)]); + } + +#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); + } + + return ret; +} + +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; + } + + memcpy(apc_opcode_handlers, zend_opcode_handlers, sizeof(apc_opcode_handlers)); + + /* 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); +} + +void apc_zend_shutdown(TSRMLS_D) +{ + if (!APCG(include_once)) { + /* Nothing changed, nothing to restore */ + return; + } + +#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 +} + +#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: + * 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 | + +----------------------------------------------------------------------+ + + 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_zend.h,v 3.8 2006/09/01 21:59:16 pollita Exp $ */ + +#ifndef APC_ZEND_H +#define APC_ZEND_H + +/* Utilities for interfacing with the zend engine */ + +#include "apc.h" +#include "apc_php.h" + +extern void* apc_php_malloc(size_t n); +extern void apc_php_free(void* p); + +extern void apc_zend_init(TSRMLS_D); +extern void apc_zend_shutdown(TSRMLS_D); + +#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/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) + +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) + +3.0.12p2: 2006-09-05 +- Package version up + +3.0,12p1: 2006-09-05 +- PHP4 build fixes + +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. + +- 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. + +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) + +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) + +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) + +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) + +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) + +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 + +3.0.3: 2005-07-05 +- Fix compile problem against PHP 5.0.x + +3.0.2: 2005-07-05 +- Better shm error message + +3.0.1: 2005-07-05 +- PHP4 build fix + +3.0: 2005-06-23 +- PHP 5.1 support (Arun, Gopal, Rasmus) +- Major Inheritance bug fix (Arun, Gopal) + +2.0: 2003-02-10 +- ground-up rewrite sharing none of the original source code (djc) + +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] + +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 + +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] + +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] + +1.0.6: +- support for mtime in mmap [yg,gws 2001-01-27] +- fixed indexed-array initialization bug [djc,gws 2001-01-27] + +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] + +1.0.4: +- support for class hierarchies greater than two levels deep [djc 2001-01-17] + +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] + +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 + +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) +]) + +PHP_ARG_ENABLE(apc, whether to enable APC support, +[ --enable-apc Enable APC support]) + +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) +]) + +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) +]) + +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) +]) + +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; + + 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; + } + + 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 + +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) +]) + +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, [ ]) + + 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 + + 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 + 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 +--------------------------------- + +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: + + 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 + +These are fully described at the bottom of this file. + +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. + +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. + +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 + ++---------------------+ +| QUICK INSTALL (DSO) | ++---------------------+ + +These instructions assume your PHP installation is located in /usr/local/php and you +want Apache optimizations (--with-apxs). + +$ 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 + +You will probably need to run the final command (make install) as root. + +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: + + extension="apc.so" + +Replace "/path/to/php/extensions" with whatever path was displayed when you +ran make install above. + +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) | ++------------------------+ + +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. + +$ cd ext +$ gunzip -c apc_x.y.tar.gz | tar xf - +$ cd .. +$ ./buildconf +$ ./config.nice +$ make +$ make install + +Once this is complete, simply restart your web server. You do not need to +modify your php.ini file to enable APC. + ++-----------------+ +| VERBOSE INSTALL | ++-----------------+ + +These instructions assume your PHP installation is located in /usr/local/php. + +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 + + This will create an apc_x.y directory. cd into this new directory: + + cd apc_x.y + +2. Run phpize. + + 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.) + + Run the phpize command: + + /usr/local/php/bin/phpize + + 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: + + ./configure --enable-apc + + php-config should be located in the same directory as phpize. + + 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. + +4. Compile and install the files. Simply type: make install + + (You may need to be root in order to install) + + If you encounter errors from libtool or gcc during this step, please + contact the project maintainer (dcowgill@php.net). + +5. Edit your php.ini + + make install should have printed a line resembling the following: + + Installing shared extensions: /path/to/extension/ + + 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): + + extension="apc.so" + + If you don't have a php.ini file in that location, you can create it now. + +6. Restart the web server and test the installation. + + 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: + + + + 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. + + 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. + ++-----------------+ +| CONFIGURING APC | ++-----------------+ + +Although the default APC settings are fine for many installations, serious +users should consider tuning the following parameters: + + 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) + + 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) + + 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) + + + 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) + + 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) + + 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: "") + + 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: "") + + 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) + + 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) + + 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) + + apc.max_file_size Prevents large files from being cached. + (Default: 1M) + + 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) + + 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) + + apc.report_autofilter Logs any scripts that were automatically excluded from being + cached due to early/late binding issues. + (Default: 0) + + 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) + + 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. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 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. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP software, freely available from + ". + +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. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see . + +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. + +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. + +Creators: + Daniel Cowgill + George Schlossnagle + +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. + +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. + +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 + +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 | + +----------------------------------------------------------------------+ + + */ + +/* $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 $ + * + *------------------------------------------------------------------------- + */ +/* #include "postgres.h" -- Removed for APC */ + +/* -- Added for APC -- */ +#include "apc.h" +#ifdef APC_SPIN_LOCKS + +#ifdef S_LOCK_TEST +#include +#endif +#ifndef WIN32 +#include +#endif +/* ---- */ + +#include +#include + +/* #include "storage/s_lock.h" -- Removed for APC */ +#include "pgsql_s_lock.h" + +static int spins_per_delay = DEFAULT_SPINS_PER_DELAY; + + +/* -- APC specific additions ------------------------------*/ +/* The following dependencies have been copied from + * other pgsql source files. The original locations + * have been noted. + */ + +/* -- from include/c.h -- */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* -- from include/pg_config_manual.h -- */ +#define MAX_RANDOM_VALUE (0x7FFFFFFF) + +/* + * 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. + */ +#define Min(x, y) ((x) < (y) ? (x) : (y)) + + +/* -- 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 + } +} + +/* -- End APC specific additions ------------------------------*/ + + +/* + * s_lock_stuck() - complain about a stuck spinlock + */ +static void +s_lock_stuck(volatile slock_t *lock, const char *file, int line) +{ +#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 +} + + +/* + * s_lock(lock) - platform-independent portion of waiting for a spinlock. + */ +void +s_lock(volatile slock_t *lock, const char *file, int line) +{ + /* + * 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 + + int spins = 0; + int delays = 0; + int cur_delay = 0; + + while (TAS(lock)) + { + /* CPU-specific delay each time through the loop */ + SPIN_DELAY(); + + /* Block the process every spins_per_delay tries */ + if (++spins >= spins_per_delay) + { + if (++delays > NUM_DELAYS) + s_lock_stuck(lock, file, line); + + if (cur_delay == 0) /* first time to delay? */ + cur_delay = MIN_DELAY_MSEC; + + pg_usleep(cur_delay * 1000L); + +#if defined(S_LOCK_TEST) + fprintf(stdout, "*"); + fflush(stdout); +#endif + + /* 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; + + 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); + } +} + + +#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; +} + +/* + * 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 + +/* + * 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 */ + + +#if defined(__GNUC__) + +/* + * All the gcc flavors that are not inlined + */ + + +/* + * 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(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 */ + + + +/*****************************************************************************/ +#if defined(S_LOCK_TEST) + +/* + * test program for verifying a port's spinlock support. + */ + +struct test_lock_struct +{ + char pad1; + slock_t lock; + char pad2; +}; + +volatile struct test_lock_struct test_lock; + +int +main() +{ + srandom((unsigned int) time(NULL)); + + test_lock.pad1 = test_lock.pad2 = 0x44; + + 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 (!S_LOCK_FREE(&test_lock.lock)) + { + printf("S_LOCK_TEST: failed, lock not initialized\n"); + return 1; + } + + S_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 (S_LOCK_FREE(&test_lock.lock)) + { + printf("S_LOCK_TEST: failed, lock not locked\n"); + return 1; + } + + S_UNLOCK(&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 (!S_LOCK_FREE(&test_lock.lock)) + { + printf("S_LOCK_TEST: failed, lock not unlocked\n"); + return 1; + } + + S_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 (S_LOCK_FREE(&test_lock.lock)) + { + printf("S_LOCK_TEST: failed, lock not re-locked\n"); + return 1; + } + + 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__); + + printf("S_LOCK_TEST: failed, lock not locked\n"); + return 1; +} + +#endif /* S_LOCK_TEST */ + +#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 | + +----------------------------------------------------------------------+ + + */ + +/* $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 + * + * $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 + +/** 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 HAVE_SPINLOCKS 1 /* -- Added for APC */ + +#ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */ + + +#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. + */ + +/*---------- + * 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 + + * 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. + *---------- + */ + + +#ifdef __i386__ /* 32-bit i386 */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +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; +} + +#define SPIN_DELAY() spin_delay() + +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__ */ + + +#ifdef __x86_64__ /* AMD Opteron, Intel EM64T */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register slock_t _res = 1; + + /* + * 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; +} + +#define SPIN_DELAY() spin_delay() + +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"); +} + +#endif /* __x86_64__ */ + + +#if defined(__ia64__) || defined(__ia64) /* Intel Itanium */ +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) tas(lock) + +#ifndef __INTEL_COMPILER + +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; +} + +#else /* __INTEL_COMPILER */ + +static __inline__ int +tas(volatile slock_t *lock) +{ + int ret; + + ret = _InterlockedExchange(lock,1); /* this is a xchg asm macro */ + + return ret; +} + +#endif /* __INTEL_COMPILER */ +#endif /* __ia64__ || __ia64 */ + + +#if defined(__arm__) || defined(__arm) +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register slock_t _res = 1; + + __asm__ __volatile__( + " swpb %0, %0, [%2] \n" +: "+r"(_res), "+m"(*lock) +: "r"(lock) +: "memory"); + return (int) _res; +} + +#endif /* __arm__ */ + + +/* S/390 and S/390x Linux (32- and 64-bit zSeries) */ +#if defined(__s390__) || defined(__s390x__) +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + int _res = 0; + + __asm__ __volatile__( + " cs %0,%3,0(%2) \n" +: "+d"(_res), "+m"(*lock) +: "a"(lock), "d"(1) +: "memory", "cc"); + return _res; +} + +#endif /* __s390__ || __s390x__ */ + + +#if defined(__sparc__) /* Sparc */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register slock_t _res; + + /* + * 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__ */ + + +/* 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. + */ +static __inline__ int +tas(volatile slock_t *lock) +{ + 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" + +: "=&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) + +#endif /* powerpc */ + + +/* Linux Motorola 68k */ +#if (defined(__mc68000__) || defined(__m68k__)) && defined(__linux__) +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register int rv; + + __asm__ __volatile__( + " clrl %0 \n" + " tas %1 \n" + " sne %0 \n" +: "=d"(rv), "+m"(*lock) +: +: "memory", "cc"); + return rv; +} + +#endif /* (__mc68000__ || __m68k__) && __linux__ */ + + +/* + * VAXen -- even multiprocessor ones + * (thanks to Tom Ivar Helbekkmo) + */ +#if defined(__vax__) +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + 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; +} + +#endif /* __vax__ */ + + +#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) +{ + 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 */ +/* + * 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; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + 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; +} + +#define S_UNLOCK(lock) \ +do \ +{\ + __asm__ __volatile__ (" mb \n"); \ + *((volatile slock_t *) (lock)) = 0; \ +} while (0) + +#endif /* __alpha || __alpha__ */ + + +#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) + +#endif /* __mips__ && !__sgi */ + + +/* These live in s_lock.c, but only for gcc */ + + +#if defined(__m68k__) && !defined(__linux__) /* non-Linux Motorola 68k */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; +#endif + + +#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 + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +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 +} + +#endif /* defined(USE_UNIVEL_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 + +typedef unsigned long slock_t; + +#include +#define S_INIT_LOCK(lock) (*(lock) = 0) +#define TAS(lock) (__LOCK_LONG_RETRY((lock), 1) == 0) +#define S_UNLOCK(lock) __UNLOCK_LONG(lock) + +#endif /* __alpha || __alpha__ */ + + +#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 + +typedef struct +{ + int sema[4]; +} slock_t; + +#define TAS_ACTIVE_WORD(lock) ((volatile int *) (((long) (lock) + 15) & ~15)) + +#if defined(__GNUC__) + +static __inline__ int +tas(volatile slock_t *lock) +{ + volatile int *lockword = TAS_ACTIVE_WORD(lock); + register int lockval; + + __asm__ __volatile__( + " ldcwx 0(0,%2),%0 \n" +: "=r"(lockval), "+m"(*lockword) +: "r"(lockword) +: "memory"); + return (lockval == 0); +} + +#endif /* __GNUC__ */ + +#define S_UNLOCK(lock) (*TAS_ACTIVE_WORD(lock) = -1) + +#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) + +#define S_LOCK_FREE(lock) (*TAS_ACTIVE_WORD(lock) != 0) + +#endif /* __hppa || __hppa__ */ + + +#if defined(__hpux) && defined(__ia64) && !defined(__GNUC__) + +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#include +#define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE) + +#endif /* HPUX on IA64, non gcc */ + + +#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. + */ +#define HAS_TEST_AND_SET + +typedef unsigned long slock_t; + +#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(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 + +#include "abi_mutex.h" +typedef abilock_t slock_t; + +#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 defined(_AIX) /* AIX */ +/* + * AIX (POWER) + */ +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) _check_lock(lock, 0, 1) +#define S_UNLOCK(lock) _clear_lock(lock, 0) +#endif /* _AIX */ + + +#if defined (nextstep) /* Nextstep */ +#define HAS_TEST_AND_SET + +typedef struct mutex slock_t; + +#define APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE 0 /* -- APC: non-blocking lock not available in this case -- */ + +#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 */ + + +/* These are in s_lock.c */ + + +#if defined(sun3) /* Sun3 */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; +#endif + + +#if defined(__sun) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc)) +#define HAS_TEST_AND_SET + +#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 __forceinline void +spin_delay(void) +{ + /* See comment for gcc code. Same code, MASM syntax */ + __asm rep nop; +} + +#endif + + +#endif /* !defined(HAS_TEST_AND_SET) */ + + +/* 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 + + +#else /* !HAVE_SPINLOCKS */ + + +/* + * 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. + */ + +/* -- 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); + +#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) +*/ + +#endif /* HAVE_SPINLOCKS */ + + +/* + * Default Definitions - override these above as needed. + */ + +#define APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE 1 /* -- APC: Non-blocking lock available for this case -- */ + +#if !defined(S_LOCK) +#define S_LOCK(lock) \ + do { \ + if (TAS(lock)) \ + s_lock((lock), __FILE__, __LINE__); \ + } while (0) +#endif /* S_LOCK */ + +#if !defined(S_LOCK_FREE) +#define S_LOCK_FREE(lock) (*(lock) == 0) +#endif /* S_LOCK_FREE */ + +#if !defined(S_UNLOCK) +#define S_UNLOCK(lock) (*((volatile slock_t *) (lock)) = 0) +#endif /* S_UNLOCK */ + +#if !defined(S_INIT_LOCK) +#define S_INIT_LOCK(lock) S_UNLOCK(lock) +#endif /* S_INIT_LOCK */ + +#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 */ + +#define TAS(lock) tas(lock) +#endif /* TAS */ + + +/* + * Platform-independent out-of-line support routines + */ +extern void s_lock(volatile slock_t *lock, const char *file, int line); + +/* Support for dynamic adjustment of spins_per_delay */ +#define DEFAULT_SPINS_PER_DELAY 100 + +#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 */ 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 | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Community Connect Inc. in 2002 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. + Future revisions and derivatives of this source code must acknowledge + Community Connect Inc. as the original contributor of this module by + leaving this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: php_apc.c,v 3.140 2007/03/28 07:14:54 gopalv Exp $ */ + +#include "apc_zend.h" +#include "apc_cache.h" +#include "apc_main.h" +#include "apc_sma.h" +#include "apc_lock.h" +#include "php_globals.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "SAPI.h" +#include "rfc1867.h" +#include "php_apc.h" +#if PHP_API_VERSION <= 20020918 +#if HAVE_APACHE +#ifdef APC_PHP4_STAT +#undef XtOffsetOf +#include "httpd.h" +#endif +#endif +#endif + +/* {{{ PHP_FUNCTION declarations */ +PHP_FUNCTION(apc_cache_info); +PHP_FUNCTION(apc_clear_cache); +PHP_FUNCTION(apc_sma_info); +PHP_FUNCTION(apc_store); +PHP_FUNCTION(apc_fetch); +PHP_FUNCTION(apc_delete); +PHP_FUNCTION(apc_compile_file); +PHP_FUNCTION(apc_define_constants); +PHP_FUNCTION(apc_load_constants); +PHP_FUNCTION(apc_add); +/* }}} */ + +/* {{{ ZEND_DECLARE_MODULE_GLOBALS(apc) */ +ZEND_DECLARE_MODULE_GLOBALS(apc) + +/* True globals */ +apc_cache_t* apc_cache = NULL; +apc_cache_t* apc_user_cache = NULL; +void* apc_compiled_filters = NULL; + +static void php_apc_init_globals(zend_apc_globals* apc_globals TSRMLS_DC) +{ + apc_globals->filters = NULL; + apc_globals->initialized = 0; + apc_globals->cache_stack = apc_stack_create(0); + apc_globals->cache_by_default = 1; + apc_globals->slam_defense = 0; + apc_globals->mem_size_ptr = NULL; + apc_globals->fpstat = 1; + apc_globals->stat_ctime = 0; + apc_globals->write_lock = 1; + apc_globals->report_autofilter = 0; + apc_globals->apc_optimize_function = NULL; +#ifdef MULTIPART_EVENT_FORMDATA + apc_globals->rfc1867 = 0; +#endif + apc_globals->copied_zvals = NULL; +#ifdef ZEND_ENGINE_2 + apc_globals->reserved_offset = -1; +#endif + apc_globals->localcache = 0; + apc_globals->localcache_size = 0; + apc_globals->lcache = NULL; +} + +static void php_apc_shutdown_globals(zend_apc_globals* apc_globals TSRMLS_DC) +{ + /* deallocate the ignore patterns */ + if (apc_globals->filters != NULL) { + int i; + for (i=0; apc_globals->filters[i] != NULL; i++) { + apc_efree(apc_globals->filters[i]); + } + apc_efree(apc_globals->filters); + } + + /* the stack should be empty */ + assert(apc_stack_size(apc_globals->cache_stack) == 0); + + /* apc cleanup */ + apc_stack_destroy(apc_globals->cache_stack); + + /* the rest of the globals are cleaned up in apc_module_shutdown() */ +} + +/* }}} */ + +/* {{{ PHP_INI */ + +static PHP_INI_MH(OnUpdate_filters) /* {{{ */ +{ + APCG(filters) = apc_tokenize(new_value, ','); + return SUCCESS; +} +/* }}} */ + +static PHP_INI_MH(OnUpdateShmSegments) /* {{{ */ +{ +#if APC_MMAP + if(atoi(new_value)!=1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "apc.shm_segments setting ignored in MMAP mode"); + } + APCG(shm_segments) = 1; +#else + APCG(shm_segments) = atoi(new_value); +#endif + return SUCCESS; +} +/* }}} */ + + +#ifdef ZEND_ENGINE_2 +#define OnUpdateInt OnUpdateLong +#endif + +PHP_INI_BEGIN() +STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.shm_size", "30", PHP_INI_SYSTEM, OnUpdateInt, shm_size, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.include_once_override", "0", PHP_INI_SYSTEM, OnUpdateBool, include_once, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.num_files_hint", "1000", PHP_INI_SYSTEM, OnUpdateInt, num_files_hint, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.user_entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateInt, user_entries_hint, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateInt, gc_ttl, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, ttl, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.user_ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, user_ttl, zend_apc_globals, apc_globals) +#if APC_MMAP +STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apc_globals, apc_globals) +#endif +PHP_INI_ENTRY("apc.filters", NULL, PHP_INI_SYSTEM, OnUpdate_filters) +STD_PHP_INI_BOOLEAN("apc.cache_by_default", "1", PHP_INI_ALL, OnUpdateBool, cache_by_default, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.slam_defense", "0", PHP_INI_SYSTEM, OnUpdateInt, slam_defense, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.file_update_protection", "2", PHP_INI_SYSTEM, OnUpdateInt,file_update_protection, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apc_globals, apc_globals) +STD_PHP_INI_ENTRY("apc.max_file_size", "1M", PHP_INI_SYSTEM, OnUpdateInt, max_file_size, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.stat", "1", PHP_INI_SYSTEM, OnUpdateBool, fpstat, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.stat_ctime", "0", PHP_INI_SYSTEM, OnUpdateBool, stat_ctime, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.write_lock", "1", PHP_INI_SYSTEM, OnUpdateBool, write_lock, zend_apc_globals, apc_globals) +STD_PHP_INI_BOOLEAN("apc.report_autofilter", "0", PHP_INI_SYSTEM, OnUpdateBool, report_autofilter,zend_apc_globals, apc_globals) +#ifdef MULTIPART_EVENT_FORMDATA +STD_PHP_INI_BOOLEAN("apc.rfc1867", "0", PHP_INI_SYSTEM, OnUpdateBool, rfc1867, zend_apc_globals, apc_globals) +#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() + +/* }}} */ + +/* {{{ 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 + +/* {{{ PHP_MINIT_FUNCTION(apc) */ +static PHP_MINIT_FUNCTION(apc) +{ + ZEND_INIT_MODULE_GLOBALS(apc, php_apc_init_globals, php_apc_shutdown_globals); + + REGISTER_INI_ENTRIES(); + + /* Disable APC in cli mode unless overridden by apc.enable_cli */ + if(!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) { + APCG(enabled) = 0; + } + + if (APCG(enabled)) { + if(APCG(initialized)) { + apc_process_init(module_number TSRMLS_CC); + } else { + apc_module_init(module_number TSRMLS_CC); + apc_zend_init(TSRMLS_C); + apc_process_init(module_number TSRMLS_CC); +#ifdef MULTIPART_EVENT_FORMDATA + /* File upload progress tracking */ + if(APCG(rfc1867)) { + php_rfc1867_callback = apc_rfc1867_progress; + } +#endif + } + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION(apc) */ +static PHP_MSHUTDOWN_FUNCTION(apc) +{ + if(APCG(enabled)) { + apc_process_shutdown(TSRMLS_C); + apc_zend_shutdown(TSRMLS_C); + apc_module_shutdown(TSRMLS_C); +#ifndef ZTS + php_apc_shutdown_globals(&apc_globals); +#endif + } +#ifdef ZTS + ts_free_id(apc_globals_id); +#endif + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RINIT_FUNCTION(apc) */ +static PHP_RINIT_FUNCTION(apc) +{ + if(APCG(enabled)) { + apc_request_init(TSRMLS_C); + } + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RSHUTDOWN_FUNCTION(apc) */ +static PHP_RSHUTDOWN_FUNCTION(apc) +{ + if(APCG(enabled)) { + apc_request_shutdown(TSRMLS_C); + } + return SUCCESS; +} +/* }}} */ + +/* {{{ proto array apc_cache_info([string type] [, bool limited]) */ +PHP_FUNCTION(apc_cache_info) +{ + apc_cache_info_t* info; + apc_cache_link_t* p; + zval* list; + char *cache_type; + int ct_len; + zend_bool limited=0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &cache_type, &ct_len, &limited) == FAILURE) { + return; + } + + if(ZEND_NUM_ARGS()) { + if(!strcasecmp(cache_type,"user")) { + info = apc_cache_info(apc_user_cache, limited); + } else { + info = apc_cache_info(apc_cache, limited); + } + } else info = apc_cache_info(apc_cache, limited); + + if(!info) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file"); + RETURN_FALSE; + } + + array_init(return_value); + add_assoc_long(return_value, "num_slots", info->num_slots); + add_assoc_long(return_value, "ttl", info->ttl); + add_assoc_long(return_value, "num_hits", info->num_hits); + add_assoc_long(return_value, "num_misses", info->num_misses); + add_assoc_long(return_value, "start_time", info->start_time); + add_assoc_long(return_value, "expunges", info->expunges); + add_assoc_long(return_value, "mem_size", info->mem_size); + add_assoc_long(return_value, "num_entries", info->num_entries); + add_assoc_long(return_value, "num_inserts", info->num_inserts); +#ifdef MULTIPART_EVENT_FORMDATA + add_assoc_long(return_value, "file_upload_progress", 1); +#else + add_assoc_long(return_value, "file_upload_progress", 0); +#endif +#if APC_MMAP + add_assoc_stringl(return_value, "memory_type", "mmap", sizeof("mmap")-1, 1); +#else + add_assoc_stringl(return_value, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1); +#endif +#if APC_SEM_LOCKS + add_assoc_stringl(return_value, "locking_type", "IPC semaphore", sizeof("IPC semaphore")-1, 1); +#elif APC_FUTEX_LOCKS + add_assoc_stringl(return_value, "locking_type", "Linux Futex", sizeof("Linux Futex")-1, 1); +#elif APC_PTHREADMUTEX_LOCKS + add_assoc_stringl(return_value, "locking_type", "pthread mutex", sizeof("pthread mutex")-1, 1); +#elif APC_SPIN_LOCKS + add_assoc_stringl(return_value, "locking_type", "spin", sizeof("spin")-1, 1); +#else + add_assoc_stringl(return_value, "locking_type", "file", sizeof("file")-1, 1); +#endif + if(limited) { + apc_cache_free_info(info); + return; + } + + ALLOC_INIT_ZVAL(list); + array_init(list); + + for (p = info->list; p != NULL; p = p->next) { + zval* link; + + ALLOC_INIT_ZVAL(link); + array_init(link); + + if(p->type == APC_CACHE_ENTRY_FILE) { + add_assoc_string(link, "filename", p->data.file.filename, 1); + add_assoc_long(link, "device", p->data.file.device); + add_assoc_long(link, "inode", p->data.file.inode); + add_assoc_string(link, "type", "file", 1); + } else if(p->type == APC_CACHE_ENTRY_USER) { + add_assoc_string(link, "info", p->data.user.info, 1); + add_assoc_long(link, "ttl", (long)p->data.user.ttl); + add_assoc_string(link, "type", "user", 1); + } + add_assoc_long(link, "num_hits", p->num_hits); + add_assoc_long(link, "mtime", p->mtime); + add_assoc_long(link, "creation_time", p->creation_time); + add_assoc_long(link, "deletion_time", p->deletion_time); + add_assoc_long(link, "access_time", p->access_time); + add_assoc_long(link, "ref_count", p->ref_count); + add_assoc_long(link, "mem_size", p->mem_size); + add_next_index_zval(list, link); + } + add_assoc_zval(return_value, "cache_list", list); + + ALLOC_INIT_ZVAL(list); + array_init(list); + + for (p = info->deleted_list; p != NULL; p = p->next) { + zval* link; + + ALLOC_INIT_ZVAL(link); + array_init(link); + + if(p->type == APC_CACHE_ENTRY_FILE) { + add_assoc_string(link, "filename", p->data.file.filename, 1); + add_assoc_long(link, "device", p->data.file.device); + add_assoc_long(link, "inode", p->data.file.inode); + add_assoc_string(link, "type", "file", 1); + } else if(p->type == APC_CACHE_ENTRY_USER) { + add_assoc_string(link, "info", p->data.user.info, 1); + add_assoc_long(link, "ttl", (long)p->data.user.ttl); + add_assoc_string(link, "type", "user", 1); + } + add_assoc_long(link, "num_hits", p->num_hits); + add_assoc_long(link, "mtime", p->mtime); + add_assoc_long(link, "creation_time", p->creation_time); + add_assoc_long(link, "deletion_time", p->deletion_time); + add_assoc_long(link, "access_time", p->access_time); + add_assoc_long(link, "ref_count", p->ref_count); + add_assoc_long(link, "mem_size", p->mem_size); + add_next_index_zval(list, link); + } + add_assoc_zval(return_value, "deleted_list", list); + + apc_cache_free_info(info); +} +/* }}} */ + +/* {{{ proto void apc_clear_cache() */ +PHP_FUNCTION(apc_clear_cache) +{ + char *cache_type; + int ct_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache_type, &ct_len) == FAILURE) { + return; + } + + if(ZEND_NUM_ARGS()) { + if(!strcasecmp(cache_type,"user")) { + apc_cache_clear(apc_user_cache); + RETURN_TRUE; + } + } + apc_cache_clear(apc_cache); +} +/* }}} */ + +/* {{{ proto array apc_sma_info([bool limited]) */ +PHP_FUNCTION(apc_sma_info) +{ + apc_sma_info_t* info; + zval* block_lists; + int i; + zend_bool limited = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &limited) == FAILURE) { + return; + } + + info = apc_sma_info(limited); + + if(!info) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC SMA info available. Perhaps APC is disabled via apc.enabled?"); + RETURN_FALSE; + } + + array_init(return_value); + add_assoc_long(return_value, "num_seg", info->num_seg); + add_assoc_long(return_value, "seg_size", info->seg_size); + add_assoc_long(return_value, "avail_mem", apc_sma_get_avail_mem()); + + if(limited) { + apc_sma_free_info(info); + return; + } + +#if ALLOC_DISTRIBUTION + { + size_t *adist = apc_sma_get_alloc_distribution(); + zval* list; + ALLOC_INIT_ZVAL(list); + array_init(list); + for(i=0; i<30; i++) { + add_next_index_long(list, adist[i]); + } + add_assoc_zval(return_value, "adist", list); + } +#endif + ALLOC_INIT_ZVAL(block_lists); + array_init(block_lists); + + for (i = 0; i < info->num_seg; i++) { + apc_sma_link_t* p; + zval* list; + + ALLOC_INIT_ZVAL(list); + array_init(list); + + for (p = info->list[i]; p != NULL; p = p->next) { + zval* link; + + ALLOC_INIT_ZVAL(link); + array_init(link); + + add_assoc_long(link, "size", p->size); + add_assoc_long(link, "offset", p->offset); + add_next_index_zval(list, link); + } + add_next_index_zval(block_lists, list); + } + add_assoc_zval(return_value, "block_lists", block_lists); + apc_sma_free_info(info); +} +/* }}} */ + +/* {{{ _apc_store */ +int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC) { + apc_cache_entry_t *entry; + apc_cache_key_t key; + time_t t; + size_t mem_size = 0; + +#if PHP_API_VERSION <= 20041225 +#if HAVE_APACHE && defined(APC_PHP4_STAT) + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif +#else + t = sapi_get_request_time(TSRMLS_C); +#endif + + if(!APCG(enabled)) return 0; + + HANDLE_BLOCK_INTERRUPTIONS(); + + APCG(mem_size_ptr) = &mem_size; + if (!(entry = apc_cache_make_user_entry(strkey, strkey_len + 1, val, ttl))) { + APCG(mem_size_ptr) = NULL; + apc_cache_expunge(apc_cache,t); + apc_cache_expunge(apc_user_cache,t); + HANDLE_UNBLOCK_INTERRUPTIONS(); + return 0; + } + + if (!apc_cache_make_user_key(&key, strkey, strkey_len + 1, t)) { + APCG(mem_size_ptr) = NULL; + apc_cache_free_entry(entry); + apc_cache_expunge(apc_cache,t); + apc_cache_expunge(apc_user_cache,t); + HANDLE_UNBLOCK_INTERRUPTIONS(); + return 0; + } + + if (!apc_cache_user_insert(apc_user_cache, key, entry, t, exclusive TSRMLS_CC)) { + APCG(mem_size_ptr) = NULL; + apc_cache_free_entry(entry); + apc_cache_expunge(apc_cache,t); + apc_cache_expunge(apc_user_cache,t); + HANDLE_UNBLOCK_INTERRUPTIONS(); + return 0; + } + + APCG(mem_size_ptr) = NULL; + + HANDLE_UNBLOCK_INTERRUPTIONS(); + + return 1; +} +/* }}} */ + +/* {{{ proto int apc_store(string key, zval var [, ttl ]) + */ +PHP_FUNCTION(apc_store) { + zval *val; + char *strkey; + int strkey_len; + long ttl = 0L; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 0 TSRMLS_CC)) RETURN_TRUE; + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto int apc_add(string key, zval var [, ttl ]) + */ +PHP_FUNCTION(apc_add) { + zval *val; + char *strkey; + int strkey_len; + long ttl = 0L; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 1 TSRMLS_CC)) RETURN_TRUE; + RETURN_FALSE; +} +/* }}} */ + +void *apc_erealloc_wrapper(void *ptr, size_t size) { + return _erealloc(ptr, size, 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); +} + +/* {{{ RETURN_ZVAL for php4 */ +#if !defined(ZEND_ENGINE_2) && !defined(RETURN_ZVAL) +#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; } +#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor) +#define ZVAL_ZVAL(z, zv, copy, dtor) { \ + int is_ref, refcount; \ + is_ref = (z)->is_ref; \ + refcount = (z)->refcount; \ + *(z) = *(zv); \ + if (copy) { \ + zval_copy_ctor(z); \ + } \ + if (dtor) { \ + if (!copy) { \ + ZVAL_NULL(zv); \ + } \ + zval_ptr_dtor(&zv); \ + } \ + (z)->is_ref = is_ref; \ + (z)->refcount = refcount; \ + } +#endif +/* }}} */ + +/* {{{ proto mixed apc_fetch(mixed key) + */ +PHP_FUNCTION(apc_fetch) { + zval *key; + HashTable *hash; + HashPosition hpos; + zval **hentry; + zval *result; + zval *result_entry; + char *strkey; + int strkey_len; + apc_cache_entry_t* entry; + time_t t; + + if(!APCG(enabled)) RETURN_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) { + return; + } + +#if PHP_API_VERSION <= 20041225 +#if HAVE_APACHE && defined(APC_PHP4_STAT) + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif +#else + t = sapi_get_request_time(TSRMLS_C); +#endif + + if(Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) { + convert_to_string(key); + } + + if(Z_TYPE_P(key) == IS_STRING) { + strkey = Z_STRVAL_P(key); + strkey_len = Z_STRLEN_P(key); + if(!strkey_len) RETURN_FALSE; + entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t); + if(entry) { + /* deep-copy returned shm zval to emalloc'ed return_value */ + apc_cache_fetch_zval(return_value, entry->data.user.val, apc_php_malloc, apc_php_free); + apc_cache_release(apc_user_cache, entry); + } else { + RETURN_FALSE; + } + } else if(Z_TYPE_P(key) == IS_ARRAY) { + hash = Z_ARRVAL_P(key); + MAKE_STD_ZVAL(result); + array_init(result); + zend_hash_internal_pointer_reset_ex(hash, &hpos); + while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) { + if(Z_TYPE_PP(hentry) != IS_STRING) { + apc_wprint("apc_fetch() expects a string or array of strings."); + RETURN_FALSE; + } + entry = apc_cache_user_find(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1, t); + if(entry) { + /* deep-copy returned shm zval to emalloc'ed return_value */ + MAKE_STD_ZVAL(result_entry); + apc_cache_fetch_zval(result_entry, entry->data.user.val, apc_php_malloc, apc_php_free); + apc_cache_release(apc_user_cache, entry); + zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1, &result_entry, sizeof(zval*), NULL); + } /* don't set values we didn't find */ + zend_hash_move_forward_ex(hash, &hpos); + } + RETURN_ZVAL(result, 0, 1); + } else { + apc_wprint("apc_fetch() expects a string or array of strings."); + RETURN_FALSE; + } + + return; +} +/* }}} */ + +/* {{{ proto mixed apc_delete(string key) + */ +PHP_FUNCTION(apc_delete) { + char *strkey; + int strkey_len; + + if(!APCG(enabled)) RETURN_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &strkey, &strkey_len) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + if(apc_cache_user_delete(apc_user_cache, strkey, strkey_len + 1)) { + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} +/* }}} */ + +static void _apc_define_constants(zval *constants, zend_bool case_sensitive TSRMLS_DC) { + char *const_key; + unsigned int const_key_len; + zval **entry; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(constants), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(constants), (void**)&entry, &pos) == SUCCESS) { + zend_constant c; + int key_type; + ulong num_key; + + key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(constants), &const_key, &const_key_len, &num_key, 0, &pos); + if(key_type != HASH_KEY_IS_STRING) { + zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); + continue; + } + switch(Z_TYPE_PP(entry)) { + case IS_LONG: + case IS_DOUBLE: + case IS_STRING: + case IS_BOOL: + case IS_RESOURCE: + case IS_NULL: + break; + default: + zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); + continue; + } + c.value = **entry; + zval_copy_ctor(&c.value); + c.flags = case_sensitive; + c.name = zend_strndup(const_key, const_key_len); + c.name_len = const_key_len; +#ifdef ZEND_ENGINE_2 + c.module_number = PHP_USER_CONSTANT; +#endif + zend_register_constant(&c TSRMLS_CC); + + zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos); + } +} + +/* {{{ proto mixed apc_define_constants(string key, array constants [,bool case-sensitive]) + */ +PHP_FUNCTION(apc_define_constants) { + char *strkey; + int strkey_len; + zval *constants = NULL; + zend_bool case_sensitive = 1; + int argc = ZEND_NUM_ARGS(); + + if (zend_parse_parameters(argc TSRMLS_CC, "sa|b", &strkey, &strkey_len, &constants, &case_sensitive) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + + _apc_define_constants(constants, case_sensitive TSRMLS_CC); + if(_apc_store(strkey, strkey_len, constants, 0, 0 TSRMLS_CC)) RETURN_TRUE; + RETURN_FALSE; +} /* }}} */ + +/* {{{ proto mixed apc_load_constants(string key [, bool case-sensitive]) + */ +PHP_FUNCTION(apc_load_constants) { + char *strkey; + int strkey_len; + apc_cache_entry_t* entry; + time_t t; + zend_bool case_sensitive = 1; + + if(!APCG(enabled)) RETURN_FALSE; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &strkey, &strkey_len, &case_sensitive) == FAILURE) { + return; + } + + if(!strkey_len) RETURN_FALSE; + +#if PHP_API_VERSION <= 20041225 +#if HAVE_APACHE && defined(APC_PHP4_STAT) + t = ((request_rec *)SG(server_context))->request_time; +#else + t = time(0); +#endif +#else + t = sapi_get_request_time(TSRMLS_C); +#endif + + entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t); + + if(entry) { + _apc_define_constants(entry->data.user.val, case_sensitive TSRMLS_CC); + apc_cache_release(apc_user_cache, entry); + RETURN_TRUE; + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto boolean apc_compile_file(string filename) + */ +PHP_FUNCTION(apc_compile_file) { + char *filename; + int filename_len; + zend_file_handle file_handle; + zend_op_array *op_array; + long slam_defense = 0; + char** filters = NULL; + zend_bool cache_by_default = 1; + HashTable cg_function_table, cg_class_table, eg_function_table, eg_class_table; + HashTable *cg_orig_function_table, *cg_orig_class_table, *eg_orig_function_table, *eg_orig_class_table; + + if(!APCG(enabled)) RETURN_FALSE; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { + return; + } + + if(!filename) RETURN_FALSE; + + /* 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; + } + + /* 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; + } + + /* 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(); + + /* 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; + + if(op_array == NULL) { RETURN_FALSE; } + + /* Free up everything */ + zend_destroy_file_handle(&file_handle TSRMLS_CC); +#ifdef ZEND_ENGINE_2 + destroy_op_array(op_array TSRMLS_CC); +#else + destroy_op_array(op_array); +#endif + efree(op_array); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ apc_functions[] */ +function_entry apc_functions[] = { + PHP_FE(apc_cache_info, NULL) + PHP_FE(apc_clear_cache, NULL) + PHP_FE(apc_sma_info, NULL) + PHP_FE(apc_store, NULL) + PHP_FE(apc_fetch, NULL) + PHP_FE(apc_delete, NULL) + PHP_FE(apc_define_constants, NULL) + PHP_FE(apc_load_constants, NULL) + PHP_FE(apc_compile_file, NULL) + {NULL, NULL, NULL} +}; +/* }}} */ + +/* {{{ module definition structure */ + +zend_module_entry apc_module_entry = { + STANDARD_MODULE_HEADER, + "apc", + apc_functions, + PHP_MINIT(apc), + PHP_MSHUTDOWN(apc), + PHP_RINIT(apc), + PHP_RSHUTDOWN(apc), + PHP_MINFO(apc), + APC_VERSION, + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_APC +ZEND_GET_MODULE(apc) +#endif +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */ Index: php-5.2.3/ext/apc/php_apc.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ php-5.2.3/ext/apc/php_apc.h 2007-07-30 10:52:17.000000000 -0500 @@ -0,0 +1,52 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ + + 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,v 3.14 2006/03/12 00:31:45 rasmus Exp $ */ + +#ifndef PHP_APC_H +#define PHP_APC_H + +#include "apc_php.h" +#include "apc_globals.h" + +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: + * 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/TECHNOTES.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ php-5.2.3/ext/apc/TECHNOTES.txt 2007-07-30 10:52:17.000000000 -0500 @@ -0,0 +1,357 @@ +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 | + +--------+-------+---------------------------------+ + + sma_shmaddrs[0] gives you the address of header + + The blocks are just a simple offset-based linked list (so no pointers): + + typedef struct block_t block_t; + struct block_t { + int size; /* size of this block */ + int next; /* offset in segment of next free block */ + }; + + The BLOCKAT macro turns an offset into an actual address for you: + + #define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset)) + + where shmaddr = sma_shaddrs[0] + + And the OFFSET macro goes the other way: + + #define OFFSET(block) ((int)(((char*)block) - (char*)shmaddr)) + + 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: + + +--------+-------+-------+-------------------------+ + | header | block | block | block | + +--------+-------+-------+-------------------------+ + + 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: + + +--------+-------+ +-------------------------+ + | header | block |------>| block | + +--------+-------+ +-------------------------+ + + 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. + + 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(). + + That should mostly take care of the low-level shared memory handling. + +6. Next up is apc_main.c and apc_cache.c which implement the meat of the + cache logic. + + 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. + + The cache is stored in/described by this struct allocated locally using + emalloc(): + + 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 */ + }; + + 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. + + 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(). + + The header looks like this: + + 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 */ + }; + + Since this is at the start of the shared memory segment, these values are accessible + across all the yapache processes and hence access to them has to be locked. + + 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: + + 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 */ + }; + + The slot_t *next there is a linked list to other slots that happened to hash to the + same array position. + + apc_cache_insert() shows what happens on a new cache insert. + + slot = &cache->slots[hash(key) % cache->num_slots]; + + cache->slots is our array of slots in the segment. hash() is simply: + + static unsigned int hash(apc_cache_key_t key) + { + return key.data.file.device + key.data.file.inode; + } + + 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. + + So, on an insert we find the array position in the slots array by hasing the device+inode. + If there are currently no other slots there, we just create the slot and stick it into + the array: + + *slot = make_slot(key, value, *slot, t) + + If there are other slots already at this position we walk the link list to get to + the end. Here is the loop: + + 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; + } + + 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. + + 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; + + struct apc_cache_key_t { + apc_cache_key_data_t data; + int mtime; /* the mtime of this cached entry */ + }; + + 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. + + 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: + + 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; + + And then the actual cache entry: + + struct apc_cache_entry_t { + apc_cache_entry_value_t data; + unsigned char type; + int ref_count; + }; + + 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. + + 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. + +7. my_compile_file() and apc_compile.c + + 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 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: + + op_array = old_compile_file(h, type TSRMLS_CC); + + 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. + +8. The Optimizer + + The optimizer has been deprecated. + +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. + 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 @@ +--TEST-- +APC: apc_store/fetch with strings +--SKIPIF-- + +--INI-- +apc.enabled=1 +apc.enable_cli=1 +apc.file_update_protection=0 +--FILE-- + +===DONE=== + +--EXPECTF-- +string(11) "hello world" +string(11) "hello world" +string(4) "nice" +===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 @@ +--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=== 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 @@ -0,0 +1,112 @@ +--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); + +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'; + } +} + +class baz extends bar +{ + private $pri = 'baz'; + + function __construct() + { + parent::__construct(); + $this->baz = true; + } +} + +$baz = new baz; +var_dump($baz); +$baz->change(); +var_dump($baz); +apc_store('baz', $baz); +unset($baz); +var_dump(apc_fetch('baz')); + +?> +===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=== 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 @@ -0,0 +1,6 @@ + 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 @@ +Known Bugs + +1. Gallery2 doesn't work with PHP5+APC. There is something wrong + with the way methods are restored in some edge case I haven't + been able to figure out yet. + To reproduce install gallery2 and click down to an individual photo. + +2. apc_store() probably needs some checks to skip trying to store + internal classes. Something along the lines of: + + if(Z_TYPE_P(val) == IS_OBJECT) { + zend_class_entry *ce = Z_OBJCE_P(val); + if(ce->type == ZEND_INTERNAL_CLASS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot cache internal objects"); + RETURN_FALSE; + } + } + + in the apc_store() function in php_apc.c but I am wondering if it needs to do more + than that. + +Enhancements + +1. Some faster platform-specific locking mechanisms wouldd be nice. futex support + for the 2.6 Linux kernels, and/or x86-specific spinlock support. + +2. The optimizer needs a lot of work. + +3. Assert() elimination in the optimizer when some debug flag somewhere isn't set. +