r5:
authorDragan Dosen <ddosen@ffzg.hr>
Fri, 4 Jan 2008 00:33:37 +0000 (00:33 +0000)
committerDragan Dosen <ddosen@ffzg.hr>
Fri, 4 Jan 2008 00:33:37 +0000 (00:33 +0000)
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.

CHANGELOG [new file with mode: 0644]
apc.c [new file with mode: 0644]
apc_globals.h [new file with mode: 0644]
apc_main.c [new file with mode: 0644]
apc_mmap.c [new file with mode: 0644]
apc_pthreadmutex.c [new file with mode: 0644]
apc_sma.c [new file with mode: 0644]
config.m4 [new file with mode: 0644]
debian/changelog
debian/control
php_apc.c [new file with mode: 0644]

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..c9de553
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,211 @@
+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]
diff --git a/apc.c b/apc.c
new file mode 100644 (file)
index 0000000..ad770f8
--- /dev/null
+++ b/apc.c
@@ -0,0 +1,554 @@
+/*
+  +----------------------------------------------------------------------+
+  | APC                                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2006 The PHP Group                                     |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Daniel Cowgill <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
+ */
diff --git a/apc_globals.h b/apc_globals.h
new file mode 100644 (file)
index 0000000..c2b2ce7
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+  +----------------------------------------------------------------------+
+  | 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
+ */
diff --git a/apc_main.c b/apc_main.c
new file mode 100644 (file)
index 0000000..50b673d
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+  +----------------------------------------------------------------------+
+  | 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
+ */
diff --git a/apc_mmap.c b/apc_mmap.c
new file mode 100644 (file)
index 0000000..8b9cccb
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+  +----------------------------------------------------------------------+
+  | 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
+ */
diff --git a/apc_pthreadmutex.c b/apc_pthreadmutex.c
new file mode 100644 (file)
index 0000000..e3b2c26
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+  +----------------------------------------------------------------------+
+  | APC                                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2006 The PHP Group                                     |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: 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
+ */
diff --git a/apc_sma.c b/apc_sma.c
new file mode 100644 (file)
index 0000000..20b8e45
--- /dev/null
+++ b/apc_sma.c
@@ -0,0 +1,628 @@
+/*
+  +----------------------------------------------------------------------+
+  | 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
+ */
diff --git a/config.m4 b/config.m4
new file mode 100644 (file)
index 0000000..c36d0df
--- /dev/null
+++ b/config.m4
@@ -0,0 +1,238 @@
+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
+
index a77c7b2..4277ece 100644 (file)
@@ -1,3 +1,10 @@
+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.
index 12dbc85..9219ebf 100644 (file)
@@ -9,7 +9,7 @@ Standards-Version: 3.7.2
 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.
diff --git a/php_apc.c b/php_apc.c
new file mode 100644 (file)
index 0000000..f7b7a7b
--- /dev/null
+++ b/php_apc.c
@@ -0,0 +1,991 @@
+/*
+  +----------------------------------------------------------------------+
+  | APC                                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2006 The PHP Group                                     |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Daniel Cowgill <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
+ */