--- /dev/null
+3.0.16: 2007-12-26
+- Fix for longstanding cache-full crash (Christian Seiler)
+ http://news.php.net/php.pecl.dev/4951 for the details
+- Added optional shm unmap on a fatal signal feature (Lucas Nealan)
+- Added PTHREAD_MUTEX_ADAPTIVE_NP option pthread locks (Paul Saab)
+- Minor cleanups (Lucas Nealan)
+- Added configure option to enable apc_cache_info('filehits') (Shire)
+
+3.0.15: 2007-10-18
+- Eliminate a per-request time() syscall (Rasmus)
+- Added rfc1867 prefix, name, and freq ini options (Shire)
+- Allow deletion of individual user cache entries via apc.php (Sara)
+- Fix overzealous cleanup during RSHUTDOWN (Gopal)
+- Fix memory alignment and locking issues (Gopal)
+- Make apc_compile insert/replace entries (Shire)
+- Make mixed inheritance recompile & cache afresh (Gopal)
+- Make nostat mode search include_path for canonicalization (Gopal)
+- ZTS & other compile fixes (Gopal, Edin, Shire)
+
+3.0.14: 2007-03-21
+- Build fix (Shire)
+- Don't hook the upload hook if APC is disabled (Rasmus)
+- Local shadow cache support (Gopal)
+- Avoid uneccessary loops over op_arrays for "known" auto-globals (Gopal)
+- Fix apc_add() to overwrite timed out user entries (Rasmus)
+- Fix double inclusion of files with conditional classes in php4 (Gopal)
+- Allocator fixes to reduce fragmentation (Gopal)
+
+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]
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <dcowgill@communityconnect.com> |
+ | George Schlossnagle <george@omniti.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ | Arun C. Murthy <arunc@yahoo-inc.com> |
+ | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: apc.c,v 3.18 2007/11/29 22:15:53 shire Exp $ */
+
+#include "apc.h"
+#include <regex.h> /* 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_DEBUG
+ 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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <dcowgill@communityconnect.com> |
+ | George Schlossnagle <george@omniti.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ | Arun C. Murthy <arunc@yahoo-inc.com> |
+ | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: apc_globals.h,v 3.70 2007/12/26 22:46:33 rasmus Exp $ */
+
+#ifndef APC_GLOBALS_H
+#define APC_GLOBALS_H
+
+#define APC_VERSION "3.0.16"
+
+#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 */
+ char* rfc1867_prefix; /* Key prefix */
+ char* rfc1867_name; /* Name of hidden field to activate upload progress/key suffix */
+ double rfc1867_freq; /* Update frequency as percentage or bytes */
+#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_bool force_file_update; /* force files to be updated during apc_compile_file */
+ char canon_path[MAXPATHLEN]; /* canonical path for key data */
+#if APC_FILEHITS
+ zval *filehits; /* Files that came from the cache for this request */
+#endif
+ zend_bool coredump_unmap; /* Trap signals that coredump and unmap shared memory */
+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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <dcowgill@communityconnect.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ | Arun C. Murthy <arunc@yahoo-inc.com> |
+ | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: apc_main.c,v 3.103 2007/11/14 19:46:46 shire 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:
+
+ 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 */
+
+ apc_cache_release(apc_cache, 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 NULL;
+}
+/* }}} */
+
+/* {{{ 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(force_file_update)) {
+ 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);
+ }
+ } else {
+ cache_entry = NULL;
+ }
+
+ if (cache_entry != NULL) {
+ 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);
+ op_array = cached_compile(h, type TSRMLS_CC);
+ if(op_array) {
+#ifdef APC_FILEHITS
+ /* If the file comes from the cache, add it to the global request file list */
+ add_next_index_string(APCG(filehits), h->filename, 1);
+#endif
+ return op_array;
+ }
+ if(APCG(report_autofilter)) {
+ apc_wprint("Recompiling %s", h->opened_path);
+ }
+ /* TODO: check what happens with EG(included_files) */
+ }
+
+ 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;
+ }
+ }
+
+ /* Make sure the mtime reflects the files last known mtime in the case of fpstat==0 */
+ if(key.type == APC_CACHE_KEY_FPFILE) {
+ apc_fileinfo_t fileinfo;
+ struct stat *tmp_buf = NULL;
+ if(!strcmp(SG(request_info).path_translated, h->filename)) {
+ tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */
+ }
+ if(tmp_buf) {
+ fileinfo.st_buf = *tmp_buf;
+ } else {
+ if (apc_search_paths(h->filename, PG(include_path), &fileinfo) != 0) {
+#ifdef __DEBUG_APC__
+ fprintf(stderr,"Stat failed %s - bailing (%s) (%d)\n",filename,SG(request_info).path_translated);
+#endif
+ return op_array;
+ }
+ }
+ key.mtime = fileinfo.st_buf.st_mtime;
+ }
+
+ 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;
+
+#ifdef APC_FILEHITS
+ ALLOC_INIT_ZVAL(APCG(filehits));
+ array_init(APCG(filehits));
+#endif
+
+ return 0;
+}
+
+int apc_request_shutdown(TSRMLS_D)
+{
+ apc_deactivate(TSRMLS_C);
+
+#ifdef APC_FILEHITS
+ zval_ptr_dtor(&APCG(filehits));
+#endif
+
+ 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.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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <rasmus@php.net> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: apc_mmap.c,v 3.7 2007/12/20 23:00:51 shire Exp $ */
+
+#include "apc.h"
+
+#if APC_MMAP
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+/*
+ * Some operating systems (like FreeBSD) have a MAP_NOSYNC flag that
+ * tells whatever update daemons might be running to not flush dirty
+ * vm pages to disk unless absolutely necessary. My guess is that
+ * most systems that don't have this probably default to only synching
+ * to disk when absolutely necessary.
+ */
+#ifndef MAP_NOSYNC
+#define MAP_NOSYNC 0
+#endif
+
+void *apc_mmap(char *file_mask, size_t 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, size_t size)
+{
+ if (munmap(shmaddr, size) < 0) {
+ apc_wprint("apc_unmap: munmap 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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <shire@php.net> |
+ +----------------------------------------------------------------------+
+
+ */
+
+/* $Id: apc_pthreadmutex.c,v 3.3 2007/12/21 01:36:51 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.");
+ }
+
+#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+ result = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+ if (result == EINVAL) {
+ apc_eprint("pthread_mutexattr_settype: unable to set adaptive mutexes");
+ }
+#endif
+
+ /* 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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <dcowgill@communityconnect.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: apc_sma.c,v 1.69 2007/12/26 21:35:39 gopalv Exp $ */
+
+#include "apc_sma.h"
+#include "apc.h"
+#include "apc_globals.h"
+#include "apc_lock.h"
+#include "apc_shm.h"
+#include <limits.h>
+#if APC_MMAP
+void *apc_mmap(char *file_mask, size_t size);
+void apc_unmap(void* shmaddr, size_t 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 size_t* 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);
+ /* if prv is the last block, jump to the beginning */
+ if(prv->next == 0) {
+ prv = BLOCKAT(ALIGNWORD(sizeof(header_t)));
+ wrapped = 1;
+ }
+ } else {
+ prv = BLOCKAT(ALIGNWORD(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(ALIGNWORD(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(ALIGNWORD(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, size_t 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 = (size_t*) apc_emalloc(sma_numseg*sizeof(size_t));
+ 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 - ALIGNWORD(sizeof(header_t)) - ALIGNWORD(sizeof(block_t));
+ header->nfoffset = 0;
+#if ALLOC_DISTRIBUTION
+ {
+ int j;
+ for(j=0; j<30; j++) header->adist[j] = 0;
+ }
+#endif
+ block = BLOCKAT(ALIGNWORD(sizeof(header_t)));
+ block->size = 0;
+ block->next = ALIGNWORD(sizeof(header_t)) + ALIGNWORD(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++) {
+ if (i == sma_lastseg) {
+ continue;
+ }
+ LOCK(((header_t*)sma_shmaddrs[i])->sma_lock);
+ 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 - ALIGNWORD(sizeof(header_t)) - ALIGNWORD(sizeof(block_t));
+
+ 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(ALIGNWORD(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 */
+size_t apc_sma_get_avail_mem()
+{
+ size_t 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(ALIGNWORD(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
+ */
--- /dev/null
+dnl
+dnl $Id: config.m4,v 3.30 2007/12/26 22:31:20 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 enable cache request file info)
+AC_ARG_ENABLE(apc-filehits,
+[ --enable-apc-filehits Enable per request file info about files used from the APC cache (ie: apc_cache_info('filehits')) ],
+[
+ PHP_APC_FILEHITS=$enableval
+ AC_MSG_RESULT($enableval)
+],
+[
+ PHP_APC_FILEHITS=no
+ AC_MSG_RESULT(no)
+])
+
+
+
+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,
+[ --disable-apc-pthreadmutex
+ Disable pthread mutex locking ],
+[
+ PHP_APC_PTHREADMUTEX=no
+ AC_MSG_RESULT(no)
+],
+[
+ PHP_APC_PTHREADMUTEX=yes
+ AC_MSG_RESULT(yes)
+])
+if test "$PHP_APC_PTHREADMUTEX" != "no"; then
+ orig_LIBS="$LIBS"
+ LIBS="$LIBS -lpthread"
+ AC_TRY_RUN(
+ [
+ #include <sys/types.h>
+ #include <pthread.h>
+ 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.");
+ 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_WARN([It doesn't appear that pthread mutex's are supported on your system])
+ PHP_APC_PTHREADMUTEX=no
+ ],
+ [
+ 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_FILEHITS" != "no" && AC_DEFINE(APC_FILEHITS, 1, [ ])
+
+ if test "$PHP_APC_SEM" != "no"; then
+ AC_DEFINE(APC_SEM_LOCKS, 1, [ ])
+ elif test "$PHP_APC_FUTEX" != "no"; then
+ AC_DEFINE(APC_FUTEX_LOCKS, 1, [ ])
+ elif test "$PHP_APC_SPINLOCKS" != "no"; then
+ AC_DEFINE(APC_SPIN_LOCKS, 1, [ ])
+ elif test "$PHP_APC_PTHREADMUTEX" != "no"; then
+ AC_DEFINE(APC_PTHREADMUTEX_LOCKS, 1, [ ])
+ fi
+
+ AC_CHECK_FUNCS(sigaction)
+ AC_CACHE_CHECK(for union semun, php_cv_semun,
+ [
+ AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+ ], [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 \
+ apc_signal.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
+
+php5-apc (3.0.16-1) stable; urgency=low
+
+ * New PHP5 APC - version 3.0.16, using PHP5 5.2.0-8+etch9,
+ 20060613+lfs.
+
+ -- Dragan Dosen <ddosen@ffzg.hr> Fri, 4 Dec 2008 00:44:23 +0100
+
php5-apc (3.0.15-1) stable; urgency=low
* Initial release for Debian etch distribution.
Package: php5-apc
Section: web
Architecture: i386
-Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= 5.2.0-8+etch7)
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= 5.2.0-8+etch9)
Conflicts: php4-apc
Description: APC module for PHP5
This package provides a module for APC functions.
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <dcowgill@communityconnect.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: php_apc.c,v 3.154 2007/12/26 22:31:20 rasmus Exp $ */
+
+#include "apc_zend.h"
+#include "apc_cache.h"
+#include "apc_main.h"
+#include "apc_sma.h"
+#include "apc_lock.h"
+#include "php_globals.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "SAPI.h"
+#include "rfc1867.h"
+#include "php_apc.h"
+#if PHP_API_VERSION <= 20020918
+#if HAVE_APACHE
+#ifdef APC_PHP4_STAT
+#undef XtOffsetOf
+#include "httpd.h"
+#endif
+#endif
+#endif
+
+#if HAVE_SIGACTION
+#include "apc_signal.h"
+#endif
+
+/* {{{ PHP_FUNCTION declarations */
+PHP_FUNCTION(apc_cache_info);
+PHP_FUNCTION(apc_clear_cache);
+PHP_FUNCTION(apc_sma_info);
+PHP_FUNCTION(apc_store);
+PHP_FUNCTION(apc_fetch);
+PHP_FUNCTION(apc_delete);
+PHP_FUNCTION(apc_compile_file);
+PHP_FUNCTION(apc_define_constants);
+PHP_FUNCTION(apc_load_constants);
+PHP_FUNCTION(apc_add);
+/* }}} */
+
+/* {{{ ZEND_DECLARE_MODULE_GLOBALS(apc) */
+ZEND_DECLARE_MODULE_GLOBALS(apc)
+
+/* True globals */
+apc_cache_t* apc_cache = NULL;
+apc_cache_t* apc_user_cache = NULL;
+void* apc_compiled_filters = NULL;
+
+static void php_apc_init_globals(zend_apc_globals* apc_globals TSRMLS_DC)
+{
+ apc_globals->filters = NULL;
+ apc_globals->initialized = 0;
+ apc_globals->cache_stack = apc_stack_create(0);
+ apc_globals->cache_by_default = 1;
+ apc_globals->slam_defense = 0;
+ apc_globals->mem_size_ptr = NULL;
+ apc_globals->fpstat = 1;
+ apc_globals->stat_ctime = 0;
+ apc_globals->write_lock = 1;
+ apc_globals->report_autofilter = 0;
+ apc_globals->apc_optimize_function = NULL;
+#ifdef MULTIPART_EVENT_FORMDATA
+ apc_globals->rfc1867 = 0;
+#endif
+ apc_globals->copied_zvals = NULL;
+#ifdef ZEND_ENGINE_2
+ apc_globals->reserved_offset = -1;
+#endif
+ apc_globals->localcache = 0;
+ apc_globals->localcache_size = 0;
+ apc_globals->lcache = NULL;
+ apc_globals->force_file_update = 0;
+ apc_globals->coredump_unmap = 0;
+}
+
+static void php_apc_shutdown_globals(zend_apc_globals* apc_globals TSRMLS_DC)
+{
+ /* deallocate the ignore patterns */
+ if (apc_globals->filters != NULL) {
+ int i;
+ for (i=0; apc_globals->filters[i] != NULL; i++) {
+ apc_efree(apc_globals->filters[i]);
+ }
+ apc_efree(apc_globals->filters);
+ }
+
+ /* the stack should be empty */
+ assert(apc_stack_size(apc_globals->cache_stack) == 0);
+
+ /* apc cleanup */
+ apc_stack_destroy(apc_globals->cache_stack);
+
+ /* the rest of the globals are cleaned up in apc_module_shutdown() */
+}
+
+/* }}} */
+
+/* {{{ PHP_INI */
+
+static PHP_INI_MH(OnUpdate_filters) /* {{{ */
+{
+ APCG(filters) = apc_tokenize(new_value, ',');
+ return SUCCESS;
+}
+/* }}} */
+
+static PHP_INI_MH(OnUpdateShmSegments) /* {{{ */
+{
+#if APC_MMAP
+ if(atoi(new_value)!=1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "apc.shm_segments setting ignored in MMAP mode");
+ }
+ APCG(shm_segments) = 1;
+#else
+ APCG(shm_segments) = atoi(new_value);
+#endif
+ return SUCCESS;
+}
+/* }}} */
+
+#ifdef MULTIPART_EVENT_FORMDATA
+static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */
+{
+ int tmp;
+ tmp = zend_atoi(new_value, new_value_length);
+ if(tmp < 0) {
+ apc_eprint("rfc1867_freq must be greater than or equal to zero.");
+ return FAILURE;
+ }
+ if(new_value[new_value_length-1] == '%') {
+ if(tmp > 100) {
+ apc_eprint("rfc1867_freq cannot be over 100%%");
+ return FAILURE;
+ }
+ APCG(rfc1867_freq) = tmp / 100.0;
+ } else {
+ APCG(rfc1867_freq) = tmp;
+ }
+ return SUCCESS;
+}
+/* }}} */
+#endif
+
+#ifdef ZEND_ENGINE_2
+#define OnUpdateInt OnUpdateLong
+#endif
+
+PHP_INI_BEGIN()
+STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.shm_size", "30", PHP_INI_SYSTEM, OnUpdateInt, shm_size, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.include_once_override", "0", PHP_INI_SYSTEM, OnUpdateBool, include_once, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.num_files_hint", "1000", PHP_INI_SYSTEM, OnUpdateInt, num_files_hint, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.user_entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateInt, user_entries_hint, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateInt, gc_ttl, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, ttl, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.user_ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, user_ttl, zend_apc_globals, apc_globals)
+#if APC_MMAP
+STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apc_globals, apc_globals)
+#endif
+PHP_INI_ENTRY("apc.filters", NULL, PHP_INI_SYSTEM, OnUpdate_filters)
+STD_PHP_INI_BOOLEAN("apc.cache_by_default", "1", PHP_INI_ALL, OnUpdateBool, cache_by_default, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.slam_defense", "0", PHP_INI_SYSTEM, OnUpdateInt, slam_defense, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.file_update_protection", "2", PHP_INI_SYSTEM, OnUpdateInt,file_update_protection, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.max_file_size", "1M", PHP_INI_SYSTEM, OnUpdateInt, max_file_size, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.stat", "1", PHP_INI_SYSTEM, OnUpdateBool, fpstat, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.stat_ctime", "0", PHP_INI_SYSTEM, OnUpdateBool, stat_ctime, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.write_lock", "1", PHP_INI_SYSTEM, OnUpdateBool, write_lock, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.report_autofilter", "0", PHP_INI_SYSTEM, OnUpdateBool, report_autofilter,zend_apc_globals, apc_globals)
+#ifdef MULTIPART_EVENT_FORMDATA
+STD_PHP_INI_BOOLEAN("apc.rfc1867", "0", PHP_INI_SYSTEM, OnUpdateBool, rfc1867, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.rfc1867_prefix", "upload_", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_prefix, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.rfc1867_name", "APC_UPLOAD_PROGRESS", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_name, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.rfc1867_freq", "0", PHP_INI_SYSTEM, OnUpdateRfc1867Freq, rfc1867_freq, zend_apc_globals, apc_globals)
+#endif
+STD_PHP_INI_BOOLEAN("apc.localcache", "0", PHP_INI_SYSTEM, OnUpdateBool, localcache, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.localcache.size", "512", PHP_INI_SYSTEM, OnUpdateInt, localcache_size, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.coredump_unmap", "0", PHP_INI_SYSTEM, OnUpdateBool, coredump_unmap, zend_apc_globals, apc_globals)
+PHP_INI_END()
+
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION(apc) */
+static PHP_MINFO_FUNCTION(apc)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "APC Support", APCG(enabled) ? "enabled" : "disabled");
+ php_info_print_table_row(2, "Version", APC_VERSION);
+#if APC_MMAP
+ php_info_print_table_row(2, "MMAP Support", "Enabled");
+ php_info_print_table_row(2, "MMAP File Mask", APCG(mmap_file_mask));
+#else
+ php_info_print_table_row(2, "MMAP Support", "Disabled");
+#endif
+#if APC_SEM_LOCKS
+ php_info_print_table_row(2, "Locking type", "IPC Semaphore");
+#elif APC_FUTEX_LOCKS
+ php_info_print_table_row(2, "Locking type", "Linux Futex Locks");
+#elif APC_PTHREADMUTEX_LOCKS
+ php_info_print_table_row(2, "Locking type", "pthread mutex Locks");
+#elif APC_SPIN_LOCKS
+ php_info_print_table_row(2, "Locking type", "spin Locks");
+#else
+ php_info_print_table_row(2, "Locking type", "File Locks");
+#endif
+ php_info_print_table_row(2, "Revision", "$Revision: 3.154 $");
+ php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__);
+ php_info_print_table_end();
+ DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+
+#ifdef MULTIPART_EVENT_FORMDATA
+extern int apc_rfc1867_progress(unsigned int event, void *event_data, void **extra TSRMLS_DC);
+#endif
+
+/* {{{ PHP_MINIT_FUNCTION(apc) */
+static PHP_MINIT_FUNCTION(apc)
+{
+ ZEND_INIT_MODULE_GLOBALS(apc, php_apc_init_globals, php_apc_shutdown_globals);
+
+ REGISTER_INI_ENTRIES();
+
+ /* Disable APC in cli mode unless overridden by apc.enable_cli */
+ if(!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) {
+ APCG(enabled) = 0;
+ }
+
+ if (APCG(enabled)) {
+ if(APCG(initialized)) {
+ apc_process_init(module_number TSRMLS_CC);
+ } else {
+ apc_module_init(module_number TSRMLS_CC);
+ apc_zend_init(TSRMLS_C);
+ apc_process_init(module_number TSRMLS_CC);
+#ifdef MULTIPART_EVENT_FORMDATA
+ /* File upload progress tracking */
+ if(APCG(rfc1867)) {
+ php_rfc1867_callback = apc_rfc1867_progress;
+ }
+#endif
+ }
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION(apc) */
+static PHP_MSHUTDOWN_FUNCTION(apc)
+{
+ if(APCG(enabled)) {
+ apc_process_shutdown(TSRMLS_C);
+ apc_zend_shutdown(TSRMLS_C);
+ apc_module_shutdown(TSRMLS_C);
+#ifndef ZTS
+ php_apc_shutdown_globals(&apc_globals);
+#endif
+ }
+#ifdef ZTS
+ ts_free_id(apc_globals_id);
+#endif
+ UNREGISTER_INI_ENTRIES();
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RINIT_FUNCTION(apc) */
+static PHP_RINIT_FUNCTION(apc)
+{
+ if(APCG(enabled)) {
+ apc_request_init(TSRMLS_C);
+
+#if HAVE_SIGACTION
+ apc_set_signals();
+#endif
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION(apc) */
+static PHP_RSHUTDOWN_FUNCTION(apc)
+{
+ if(APCG(enabled)) {
+ apc_request_shutdown(TSRMLS_C);
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ proto array apc_cache_info([string type] [, bool limited]) */
+PHP_FUNCTION(apc_cache_info)
+{
+ apc_cache_info_t* info;
+ apc_cache_link_t* p;
+ zval* list;
+ char *cache_type;
+ int ct_len;
+ zend_bool limited=0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &cache_type, &ct_len, &limited) == FAILURE) {
+ return;
+ }
+
+ if(ZEND_NUM_ARGS()) {
+ if(!strcasecmp(cache_type,"user")) {
+ info = apc_cache_info(apc_user_cache, limited);
+ } else if(!strcasecmp(cache_type,"filehits")) {
+#ifdef APC_FILEHITS
+ RETVAL_ZVAL(APCG(filehits), 1, 0);
+ return;
+#else
+ RETURN_FALSE;
+#endif
+ } else {
+ info = apc_cache_info(apc_cache, limited);
+ }
+ } else info = apc_cache_info(apc_cache, limited);
+
+ if(!info) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file");
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ add_assoc_long(return_value, "num_slots", info->num_slots);
+ add_assoc_long(return_value, "ttl", info->ttl);
+ add_assoc_long(return_value, "num_hits", info->num_hits);
+ add_assoc_long(return_value, "num_misses", info->num_misses);
+ add_assoc_long(return_value, "start_time", info->start_time);
+ add_assoc_long(return_value, "expunges", info->expunges);
+ add_assoc_long(return_value, "mem_size", info->mem_size);
+ add_assoc_long(return_value, "num_entries", info->num_entries);
+ add_assoc_long(return_value, "num_inserts", info->num_inserts);
+#ifdef MULTIPART_EVENT_FORMDATA
+ add_assoc_long(return_value, "file_upload_progress", 1);
+#else
+ add_assoc_long(return_value, "file_upload_progress", 0);
+#endif
+#if APC_MMAP
+ add_assoc_stringl(return_value, "memory_type", "mmap", sizeof("mmap")-1, 1);
+#else
+ add_assoc_stringl(return_value, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1);
+#endif
+#if APC_SEM_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "IPC semaphore", sizeof("IPC semaphore")-1, 1);
+#elif APC_FUTEX_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "Linux Futex", sizeof("Linux Futex")-1, 1);
+#elif APC_PTHREADMUTEX_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "pthread mutex", sizeof("pthread mutex")-1, 1);
+#elif APC_SPIN_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "spin", sizeof("spin")-1, 1);
+#else
+ add_assoc_stringl(return_value, "locking_type", "file", sizeof("file")-1, 1);
+#endif
+ if(limited) {
+ apc_cache_free_info(info);
+ return;
+ }
+
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+
+ for (p = info->list; p != NULL; p = p->next) {
+ zval* link;
+
+ ALLOC_INIT_ZVAL(link);
+ array_init(link);
+
+ if(p->type == APC_CACHE_ENTRY_FILE) {
+ add_assoc_string(link, "filename", p->data.file.filename, 1);
+ add_assoc_long(link, "device", p->data.file.device);
+ add_assoc_long(link, "inode", p->data.file.inode);
+ add_assoc_string(link, "type", "file", 1);
+ } else if(p->type == APC_CACHE_ENTRY_USER) {
+ add_assoc_string(link, "info", p->data.user.info, 1);
+ add_assoc_long(link, "ttl", (long)p->data.user.ttl);
+ add_assoc_string(link, "type", "user", 1);
+ }
+ add_assoc_long(link, "num_hits", p->num_hits);
+ add_assoc_long(link, "mtime", p->mtime);
+ add_assoc_long(link, "creation_time", p->creation_time);
+ add_assoc_long(link, "deletion_time", p->deletion_time);
+ add_assoc_long(link, "access_time", p->access_time);
+ add_assoc_long(link, "ref_count", p->ref_count);
+ add_assoc_long(link, "mem_size", p->mem_size);
+ add_next_index_zval(list, link);
+ }
+ add_assoc_zval(return_value, "cache_list", list);
+
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+
+ for (p = info->deleted_list; p != NULL; p = p->next) {
+ zval* link;
+
+ ALLOC_INIT_ZVAL(link);
+ array_init(link);
+
+ if(p->type == APC_CACHE_ENTRY_FILE) {
+ add_assoc_string(link, "filename", p->data.file.filename, 1);
+ add_assoc_long(link, "device", p->data.file.device);
+ add_assoc_long(link, "inode", p->data.file.inode);
+ add_assoc_string(link, "type", "file", 1);
+ } else if(p->type == APC_CACHE_ENTRY_USER) {
+ add_assoc_string(link, "info", p->data.user.info, 1);
+ add_assoc_long(link, "ttl", (long)p->data.user.ttl);
+ add_assoc_string(link, "type", "user", 1);
+ }
+ add_assoc_long(link, "num_hits", p->num_hits);
+ add_assoc_long(link, "mtime", p->mtime);
+ add_assoc_long(link, "creation_time", p->creation_time);
+ add_assoc_long(link, "deletion_time", p->deletion_time);
+ add_assoc_long(link, "access_time", p->access_time);
+ add_assoc_long(link, "ref_count", p->ref_count);
+ add_assoc_long(link, "mem_size", p->mem_size);
+ add_next_index_zval(list, link);
+ }
+ add_assoc_zval(return_value, "deleted_list", list);
+
+ apc_cache_free_info(info);
+}
+/* }}} */
+
+/* {{{ proto void apc_clear_cache() */
+PHP_FUNCTION(apc_clear_cache)
+{
+ char *cache_type;
+ int ct_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache_type, &ct_len) == FAILURE) {
+ return;
+ }
+
+ if(ZEND_NUM_ARGS()) {
+ if(!strcasecmp(cache_type,"user")) {
+ apc_cache_clear(apc_user_cache);
+ RETURN_TRUE;
+ }
+ }
+ apc_cache_clear(apc_cache);
+}
+/* }}} */
+
+/* {{{ proto array apc_sma_info([bool limited]) */
+PHP_FUNCTION(apc_sma_info)
+{
+ apc_sma_info_t* info;
+ zval* block_lists;
+ int i;
+ zend_bool limited = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &limited) == FAILURE) {
+ return;
+ }
+
+ info = apc_sma_info(limited);
+
+ if(!info) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC SMA info available. Perhaps APC is disabled via apc.enabled?");
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ add_assoc_long(return_value, "num_seg", info->num_seg);
+ add_assoc_long(return_value, "seg_size", info->seg_size);
+ add_assoc_long(return_value, "avail_mem", apc_sma_get_avail_mem());
+
+ if(limited) {
+ apc_sma_free_info(info);
+ return;
+ }
+
+#if ALLOC_DISTRIBUTION
+ {
+ size_t *adist = apc_sma_get_alloc_distribution();
+ zval* list;
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+ for(i=0; i<30; i++) {
+ add_next_index_long(list, adist[i]);
+ }
+ add_assoc_zval(return_value, "adist", list);
+ }
+#endif
+ ALLOC_INIT_ZVAL(block_lists);
+ array_init(block_lists);
+
+ for (i = 0; i < info->num_seg; i++) {
+ apc_sma_link_t* p;
+ zval* list;
+
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+
+ for (p = info->list[i]; p != NULL; p = p->next) {
+ zval* link;
+
+ ALLOC_INIT_ZVAL(link);
+ array_init(link);
+
+ add_assoc_long(link, "size", p->size);
+ add_assoc_long(link, "offset", p->offset);
+ add_next_index_zval(list, link);
+ }
+ add_next_index_zval(block_lists, list);
+ }
+ add_assoc_zval(return_value, "block_lists", block_lists);
+ apc_sma_free_info(info);
+}
+/* }}} */
+
+/* {{{ _apc_store */
+int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC) {
+ apc_cache_entry_t *entry;
+ apc_cache_key_t key;
+ time_t t;
+ size_t mem_size = 0;
+
+#if PHP_API_VERSION < 20041225
+#if HAVE_APACHE && defined(APC_PHP4_STAT)
+ t = ((request_rec *)SG(server_context))->request_time;
+#else
+ t = time(0);
+#endif
+#else
+ t = sapi_get_request_time(TSRMLS_C);
+#endif
+
+ if(!APCG(enabled)) return 0;
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+
+ APCG(mem_size_ptr) = &mem_size;
+ if (!(entry = apc_cache_make_user_entry(strkey, strkey_len + 1, val, ttl))) {
+ APCG(mem_size_ptr) = NULL;
+ apc_cache_expunge(apc_cache,t);
+ apc_cache_expunge(apc_user_cache,t);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return 0;
+ }
+
+ if (!apc_cache_make_user_key(&key, strkey, strkey_len + 1, t)) {
+ APCG(mem_size_ptr) = NULL;
+ apc_cache_free_entry(entry);
+ apc_cache_expunge(apc_cache,t);
+ apc_cache_expunge(apc_user_cache,t);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return 0;
+ }
+
+ if (!apc_cache_user_insert(apc_user_cache, key, entry, t, exclusive TSRMLS_CC)) {
+ APCG(mem_size_ptr) = NULL;
+ apc_cache_free_entry(entry);
+ apc_cache_expunge(apc_cache,t);
+ apc_cache_expunge(apc_user_cache,t);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return 0;
+ }
+
+ APCG(mem_size_ptr) = NULL;
+
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ proto int apc_store(string key, zval var [, ttl ])
+ */
+PHP_FUNCTION(apc_store) {
+ zval *val;
+ char *strkey;
+ int strkey_len;
+ long ttl = 0L;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 0 TSRMLS_CC)) RETURN_TRUE;
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int apc_add(string key, zval var [, ttl ])
+ */
+PHP_FUNCTION(apc_add) {
+ zval *val;
+ char *strkey;
+ int strkey_len;
+ long ttl = 0L;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 1 TSRMLS_CC)) RETURN_TRUE;
+ RETURN_FALSE;
+}
+/* }}} */
+
+void *apc_erealloc_wrapper(void *ptr, size_t size) {
+ return _erealloc(ptr, size, 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
+}
+
+/* {{{ RETURN_ZVAL for php4 */
+#if !defined(ZEND_ENGINE_2) && !defined(RETURN_ZVAL)
+#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; }
+#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor)
+#define ZVAL_ZVAL(z, zv, copy, dtor) { \
+ int is_ref, refcount; \
+ is_ref = (z)->is_ref; \
+ refcount = (z)->refcount; \
+ *(z) = *(zv); \
+ if (copy) { \
+ zval_copy_ctor(z); \
+ } \
+ if (dtor) { \
+ if (!copy) { \
+ ZVAL_NULL(zv); \
+ } \
+ zval_ptr_dtor(&zv); \
+ } \
+ (z)->is_ref = is_ref; \
+ (z)->refcount = refcount; \
+ }
+#endif
+/* }}} */
+
+/* {{{ proto mixed apc_fetch(mixed key)
+ */
+PHP_FUNCTION(apc_fetch) {
+ zval *key;
+ HashTable *hash;
+ HashPosition hpos;
+ zval **hentry;
+ zval *result;
+ zval *result_entry;
+ char *strkey;
+ int strkey_len;
+ apc_cache_entry_t* entry;
+ time_t t;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) {
+ return;
+ }
+
+#if PHP_API_VERSION < 20041225
+#if HAVE_APACHE && defined(APC_PHP4_STAT)
+ t = ((request_rec *)SG(server_context))->request_time;
+#else
+ t = time(0);
+#endif
+#else
+ t = sapi_get_request_time(TSRMLS_C);
+#endif
+
+ if(Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) {
+ convert_to_string(key);
+ }
+
+ if(Z_TYPE_P(key) == IS_STRING) {
+ strkey = Z_STRVAL_P(key);
+ strkey_len = Z_STRLEN_P(key);
+ if(!strkey_len) RETURN_FALSE;
+ entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t);
+ if(entry) {
+ /* deep-copy returned shm zval to emalloc'ed return_value */
+ apc_cache_fetch_zval(return_value, entry->data.user.val, apc_php_malloc, apc_php_free);
+ apc_cache_release(apc_user_cache, entry);
+ } else {
+ RETURN_FALSE;
+ }
+ } else if(Z_TYPE_P(key) == IS_ARRAY) {
+ hash = Z_ARRVAL_P(key);
+ MAKE_STD_ZVAL(result);
+ array_init(result);
+ zend_hash_internal_pointer_reset_ex(hash, &hpos);
+ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) {
+ if(Z_TYPE_PP(hentry) != IS_STRING) {
+ apc_wprint("apc_fetch() expects a string or array of strings.");
+ RETURN_FALSE;
+ }
+ entry = apc_cache_user_find(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1, t);
+ if(entry) {
+ /* deep-copy returned shm zval to emalloc'ed return_value */
+ MAKE_STD_ZVAL(result_entry);
+ apc_cache_fetch_zval(result_entry, entry->data.user.val, apc_php_malloc, apc_php_free);
+ apc_cache_release(apc_user_cache, entry);
+ zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1, &result_entry, sizeof(zval*), NULL);
+ } /* don't set values we didn't find */
+ zend_hash_move_forward_ex(hash, &hpos);
+ }
+ RETURN_ZVAL(result, 0, 1);
+ } else {
+ apc_wprint("apc_fetch() expects a string or array of strings.");
+ RETURN_FALSE;
+ }
+
+ return;
+}
+/* }}} */
+
+/* {{{ proto mixed apc_delete(string key)
+ */
+PHP_FUNCTION(apc_delete) {
+ char *strkey;
+ int strkey_len;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &strkey, &strkey_len) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ if(apc_cache_user_delete(apc_user_cache, strkey, strkey_len + 1)) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+static void _apc_define_constants(zval *constants, zend_bool case_sensitive TSRMLS_DC) {
+ char *const_key;
+ unsigned int const_key_len;
+ zval **entry;
+ HashPosition pos;
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(constants), &pos);
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(constants), (void**)&entry, &pos) == SUCCESS) {
+ zend_constant c;
+ int key_type;
+ ulong num_key;
+
+ key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(constants), &const_key, &const_key_len, &num_key, 0, &pos);
+ if(key_type != HASH_KEY_IS_STRING) {
+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos);
+ continue;
+ }
+ switch(Z_TYPE_PP(entry)) {
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_BOOL:
+ case IS_RESOURCE:
+ case IS_NULL:
+ break;
+ default:
+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos);
+ continue;
+ }
+ c.value = **entry;
+ zval_copy_ctor(&c.value);
+ c.flags = case_sensitive;
+ c.name = zend_strndup(const_key, const_key_len);
+ c.name_len = const_key_len;
+#ifdef ZEND_ENGINE_2
+ c.module_number = PHP_USER_CONSTANT;
+#endif
+ zend_register_constant(&c TSRMLS_CC);
+
+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos);
+ }
+}
+
+/* {{{ proto mixed apc_define_constants(string key, array constants [,bool case-sensitive])
+ */
+PHP_FUNCTION(apc_define_constants) {
+ char *strkey;
+ int strkey_len;
+ zval *constants = NULL;
+ zend_bool case_sensitive = 1;
+ int argc = ZEND_NUM_ARGS();
+
+ if (zend_parse_parameters(argc TSRMLS_CC, "sa|b", &strkey, &strkey_len, &constants, &case_sensitive) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ _apc_define_constants(constants, case_sensitive TSRMLS_CC);
+ if(_apc_store(strkey, strkey_len, constants, 0, 0 TSRMLS_CC)) RETURN_TRUE;
+ RETURN_FALSE;
+} /* }}} */
+
+/* {{{ proto mixed apc_load_constants(string key [, bool case-sensitive])
+ */
+PHP_FUNCTION(apc_load_constants) {
+ char *strkey;
+ int strkey_len;
+ apc_cache_entry_t* entry;
+ time_t t;
+ zend_bool case_sensitive = 1;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &strkey, &strkey_len, &case_sensitive) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+#if PHP_API_VERSION < 20041225
+#if HAVE_APACHE && defined(APC_PHP4_STAT)
+ t = ((request_rec *)SG(server_context))->request_time;
+#else
+ t = time(0);
+#endif
+#else
+ t = sapi_get_request_time(TSRMLS_C);
+#endif
+
+ entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t);
+
+ if(entry) {
+ _apc_define_constants(entry->data.user.val, case_sensitive TSRMLS_CC);
+ apc_cache_release(apc_user_cache, entry);
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto boolean apc_compile_file(string filename)
+ */
+PHP_FUNCTION(apc_compile_file) {
+ char *filename;
+ int filename_len;
+ zend_file_handle file_handle;
+ zend_op_array *op_array;
+ long slam_defense = 0;
+ char** filters = NULL;
+ zend_bool cache_by_default = 1;
+ HashTable cg_function_table, cg_class_table, eg_function_table, eg_class_table;
+ HashTable *cg_orig_function_table, *cg_orig_class_table, *eg_orig_function_table, *eg_orig_class_table;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+ return;
+ }
+
+ if(!filename) RETURN_FALSE;
+
+ /* reset slam defense, filters, and cache_by_default */
+ slam_defense = APCG(slam_defense);
+ APCG(slam_defense) = 0;
+
+ filters = APCG(filters);
+ APCG(filters) = NULL;
+
+ cache_by_default = APCG(cache_by_default);
+ APCG(cache_by_default) = 1;
+
+ /* Replace function/class tables to avoid namespace conflicts */
+ zend_hash_init_ex(&cg_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
+ cg_orig_function_table = CG(function_table);
+ CG(function_table) = &cg_function_table;
+ zend_hash_init_ex(&cg_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
+ cg_orig_class_table = CG(class_table);
+ CG(class_table) = &cg_class_table;
+ eg_orig_function_table = EG(function_table);
+ EG(function_table) = CG(function_table);
+ eg_orig_class_table = EG(class_table);
+ EG(class_table) = CG(class_table);
+ APCG(force_file_update) = 1;
+
+ /* Compile the file, loading it into the cache */
+ file_handle.type = ZEND_HANDLE_FILENAME;
+ file_handle.filename = filename;
+ file_handle.free_filename = 0;
+ file_handle.opened_path = NULL;
+ zend_try {
+ op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
+ } zend_catch {
+ apc_wprint("Error compiling %s in apc_compile_file.", filename);
+ op_array = NULL;
+ } zend_end_try();
+
+ /* Return class/function tables to previous states, destroy temp tables */
+ APCG(force_file_update) = 0;
+ CG(function_table) = cg_orig_function_table;
+ zend_hash_destroy(&cg_function_table);
+ CG(class_table) = cg_orig_class_table;
+ zend_hash_destroy(&cg_class_table);
+ EG(function_table) = eg_orig_function_table;
+ EG(class_table) = eg_orig_class_table;
+
+ /* Restore global settings */
+ APCG(slam_defense) = slam_defense;
+ APCG(filters) = filters;
+ APCG(cache_by_default) = cache_by_default;
+
+ if(op_array == NULL) { RETURN_FALSE; }
+
+ /* Free up everything */
+ zend_destroy_file_handle(&file_handle TSRMLS_CC);
+#ifdef ZEND_ENGINE_2
+ destroy_op_array(op_array TSRMLS_CC);
+#else
+ destroy_op_array(op_array);
+#endif
+ efree(op_array);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ apc_functions[] */
+function_entry apc_functions[] = {
+ PHP_FE(apc_cache_info, NULL)
+ PHP_FE(apc_clear_cache, NULL)
+ PHP_FE(apc_sma_info, NULL)
+ PHP_FE(apc_store, NULL)
+ PHP_FE(apc_fetch, NULL)
+ PHP_FE(apc_delete, NULL)
+ PHP_FE(apc_define_constants, NULL)
+ PHP_FE(apc_load_constants, NULL)
+ PHP_FE(apc_compile_file, NULL)
+ PHP_FE(apc_add, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ module definition structure */
+
+zend_module_entry apc_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "apc",
+ apc_functions,
+ PHP_MINIT(apc),
+ PHP_MSHUTDOWN(apc),
+ PHP_RINIT(apc),
+ PHP_RSHUTDOWN(apc),
+ PHP_MINFO(apc),
+ APC_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_APC
+ZEND_GET_MODULE(apc)
+#endif
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: expandtab sw=4 ts=4 sts=4
+ */