add option to compile APC for php5
authorTim Yardley <lst@openwrt.org>
Wed, 18 Jul 2007 16:35:41 +0000 (16:35 +0000)
committerTim Yardley <lst@openwrt.org>
Wed, 18 Jul 2007 16:35:41 +0000 (16:35 +0000)
SVN-Revision: 8043

lang/php5/Makefile
lang/php5/patches/005-APC.patch [new file with mode: 0644]

index 5da72cb..2690854 100644 (file)
@@ -150,6 +150,12 @@ define Package/php5-mod-xml
   TITLE:=XML module
 endef
 
+define Package/php5-mod-apc
+  $(call Package/php5/Default)
+  DEPENDS:=php5
+  TITLE:=APC Extension
+endef
+
 PKG_CONFIGURE_LIBS:= -lcrypto -lssl
 PKG_CONFIGURE_OPTS:= \
        --enable-shared \
@@ -259,6 +265,12 @@ ifneq ($(CONFIG_PACKAGE_php5-mod-xml),)
 else
   PKG_CONFIGURE_OPTS+= --disable-xml
 endif
+ifneq ($(CONFIG_PACKAGE_php5-mod-apc),)
+  PKG_CONFIGURE_OPTS+= --enable-apc --disable-apc-mmap
+  PKG_CONFIGURE_LIBS+= -lrt
+else
+  PKG_CONFIGURE_OPTS+= --disable-apc
+endif
 
 define Build/Configure
 endef
@@ -304,6 +316,8 @@ endif
 ifneq ($(CONFIG_PACKAGE_php5-fastcgi),)
   define Build/Compile/php5-fastcgi
        -$(MAKE) -C $(PKG_BUILD_DIR) clean
+       rm $(PKG_BUILD_DIR)/configure
+       cd $(PKG_BUILD_DIR) && ./buildconf --force
        $(call Build/Configure/Default, \
                $(PKG_CONFIGURE_OPTS) \
                --disable-cli \
@@ -376,3 +390,4 @@ $(eval $(call BuildPlugin,php5-mod-session,session))
 $(eval $(call BuildPlugin,php5-mod-sockets,sockets))
 $(eval $(call BuildPlugin,php5-mod-sqlite,sqlite))
 $(eval $(call BuildPlugin,php5-mod-xml,xml))
+$(eval $(call BuildPlugin,php5-mod-apc))
diff --git a/lang/php5/patches/005-APC.patch b/lang/php5/patches/005-APC.patch
new file mode 100644 (file)
index 0000000..c353758
--- /dev/null
@@ -0,0 +1,14327 @@
+diff -ruN php-5.1.6.old/ext/apc/apc.c php-5.1.6/ext/APC/apc.c
+--- php-5.1.6.old/ext/apc/apc.c        1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc.c    2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,554 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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.17 2007/03/17 14:01:41 gopalv 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_DBG
++    va_list args;
++    va_start(args, fmt);
++    my_log(APC_DBG, fmt, args);
++    va_end(args);
++#endif
++}
++
++/* }}} */
++
++/* {{{ string and text manipulation */
++
++char* apc_append(const char* s, const char* t)
++{
++    int slen;
++    int tlen;
++    char* p;
++
++    slen = strlen(s);
++    tlen = strlen(t);
++
++    p = (char*) apc_emalloc((slen + tlen + 1) * sizeof(char));
++    memcpy(p, s, slen);
++    memcpy(p + slen, t, tlen + 1);
++
++    return p;
++}
++
++char* apc_substr(const char* s, int start, int length)
++{
++    char* substr;
++    int src_len = strlen(s);
++
++    /* bring start into range */
++    if (start < 0) {
++        start = 0;
++    }
++    else if (start >= src_len) {
++        start = src_len - 1;
++    }
++
++    /* bring length into range */
++    if (length < 0 || src_len - start < length) {
++        length = src_len - start;
++    }
++
++    /* create the substring */
++    substr = apc_xmemcpy(s + start, length + 1, apc_emalloc);
++    substr[length] = '\0';
++    return substr;
++}
++
++char** apc_tokenize(const char* s, char delim)
++{
++    char** tokens;      /* array of tokens, NULL terminated */
++    int size;           /* size of tokens array */
++    int n;              /* index of next token in tokens array */
++    int cur;            /* current position in input string */
++    int end;            /* final legal position in input string */
++    int next;           /* position of next delimiter in input */
++    
++    if (!s) {
++        return NULL;
++    }
++
++    size = 2;
++    n    = 0;
++    cur  = 0;
++    end  = strlen(s) - 1;
++    
++    tokens = (char**) apc_emalloc(size * sizeof(char*));
++    tokens[n] = NULL;
++
++    while (cur <= end) {
++        /* search for the next delimiter */
++        char* p = strchr(s + cur, delim);
++        next = p ? p-s : end+1;
++
++        /* resize token array if necessary */
++        if (n == size-1) {
++            size *= 2;
++            tokens = (char**) apc_erealloc(tokens, size * sizeof(char*));
++        }
++
++        /* save the current token */
++        tokens[n] = apc_substr(s, cur, next-cur);
++
++        tokens[++n] = NULL;
++        cur = next + 1;
++    }
++
++    return tokens;
++}
++
++/* }}} */
++
++/* {{{ filesystem functions */
++
++#ifdef PHP_WIN32
++int apc_win32_stat(const char *path, struct stat *buf TSRMLS_DC)
++{
++    char rpath[MAXPATHLEN];
++    BY_HANDLE_FILE_INFORMATION fi;
++    HANDLE f;
++    
++    if (VCWD_STAT(path, buf)) {
++        return -1;
++    }
++
++    VCWD_REALPATH(path, rpath);
++    f = CreateFile(rpath, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL);
++    GetFileInformationByHandle(f, &fi);
++    buf->st_ino = (ino_t)fi.nFileIndexLow;
++    CloseHandle (f);
++    return 0;
++}
++#endif
++
++int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo)
++{
++    char** paths;
++    char *exec_fname;
++    int exec_fname_length;
++    int found = 0;
++    int i;
++    TSRMLS_FETCH();
++
++    assert(filename && fileinfo);
++
++    if (IS_ABSOLUTE_PATH(filename, strlen(filename)) && apc_stat(filename, &fileinfo->st_buf) == 0) {
++        strncpy(fileinfo->fullpath, filename, MAXPATHLEN);
++        return 0;
++    }
++
++    paths = apc_tokenize(path, DEFAULT_DIR_SEPARATOR);
++    if (!paths)
++        return -1;
++
++    /* for each directory in paths, look for filename inside */
++    for (i = 0; paths[i]; i++) {
++        snprintf(fileinfo->fullpath, sizeof(fileinfo->fullpath), "%s%c%s", paths[i], DEFAULT_SLASH, filename);
++        if (apc_stat(fileinfo->fullpath, &fileinfo->st_buf) == 0) {
++            found = 1;
++            break;
++        }
++    }
++
++    /* check in path of the calling scripts' current working directory */
++    /* modified from main/streams/plain_wrapper.c */
++    if(!found && zend_is_executing(TSRMLS_C)) {
++        exec_fname = zend_get_executed_filename(TSRMLS_C);
++        exec_fname_length = strlen(exec_fname);
++        while((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
++        if((exec_fname && exec_fname[0] != '[') && exec_fname_length > 0) {
++            /* not: [no active file] or no path */
++            memcpy(fileinfo->fullpath, exec_fname, exec_fname_length);
++            fileinfo->fullpath[exec_fname_length] = DEFAULT_SLASH;
++            strcpy(fileinfo->fullpath +exec_fname_length +1, filename);
++            /* apc_wprint("filename: %s, exec_fname: %s, fileinfo->fullpath: %s", filename, exec_fname, fileinfo->fullpath); */
++            if (apc_stat(fileinfo->fullpath, &fileinfo->st_buf) == 0) {
++                found = 1;
++            }
++        }
++    }
++    
++    /* free the value returned by apc_tokenize */
++    for (i = 0; paths[i]; i++) {
++        apc_efree(paths[i]);
++    }
++    apc_efree(paths);
++
++    return found ? 0 : -1;
++}
++
++/* }}} */
++
++/* {{{ regular expression wrapper functions */
++
++typedef struct {
++    regex_t *reg;
++    unsigned char type;
++} apc_regex;
++
++void* apc_regex_compile_array(char* patterns[])
++{
++    apc_regex** regs;
++    int npat;
++    int i;
++
++    if (!patterns)
++        return NULL;
++
++    /* count the number of patterns in patterns */
++    for (npat = 0; patterns[npat] != NULL; npat++) {}
++
++    if (npat == 0)
++        return NULL;
++
++    /* allocate the array of compiled expressions */
++    regs = (apc_regex**) apc_emalloc(sizeof(apc_regex*) * (npat + 1));
++    for (i = 0; i <= npat; i++) {
++        regs[i] = (apc_regex *) apc_emalloc(sizeof(apc_regex));
++        regs[i]->reg = NULL;
++        regs[i]->type = APC_NEGATIVE_MATCH;
++    }
++
++    /* compile the expressions */
++    for (i = 0; i < npat; i++) {
++        char *pattern = patterns[i];
++        if(pattern[0]=='+') { regs[i]->type = APC_POSITIVE_MATCH; pattern = patterns[i]+sizeof(char); }
++        else if(pattern[0]=='-') { regs[i]->type = APC_NEGATIVE_MATCH; pattern = patterns[i]+sizeof(char); }
++
++        regs[i]->reg = (regex_t*) apc_emalloc(sizeof(regex_t));
++
++        if (regcomp(regs[i]->reg, pattern, REG_EXTENDED | REG_NOSUB) != 0) {
++            apc_wprint("apc_regex_compile_array: invalid expression '%s'",
++                       pattern);
++
++            apc_regex_destroy_array(regs);
++
++            return NULL;
++        }
++    }
++
++    return (void*) regs;
++}
++
++void apc_regex_destroy_array(void* p)
++{
++    if (p != NULL) {
++        apc_regex** regs = (apc_regex**) p;
++        int i;
++
++        for (i = 0; regs[i]->reg != NULL; i++) {
++            regfree(regs[i]->reg);
++            apc_efree(regs[i]->reg);
++            apc_efree(regs[i]);
++        }
++        apc_efree(regs);
++    }
++}
++
++int apc_regex_match_array(void* p, const char* input)
++{
++    apc_regex** regs;
++    int i;
++
++    if (!p)
++        return 0;
++
++    regs = (apc_regex**) p;
++    for (i = 0; regs[i]->reg != NULL; i++)
++        if (regexec(regs[i]->reg, input, 0, NULL, 0) == 0)
++            return (int)(regs[i]->type);
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ crc32 implementation */
++
++/* this table was generated by crc32gen() */
++static unsigned int crc32tab[] = {
++    /*   0 */  0x00000000, 0x3b83984b, 0x77073096, 0x4c84a8dd, 
++    /*   4 */  0xee0e612c, 0xd58df967, 0x990951ba, 0xa28ac9f1, 
++    /*   8 */  0x076dc419, 0x3cee5c52, 0x706af48f, 0x4be96cc4, 
++    /*  12 */  0xe963a535, 0xd2e03d7e, 0x9e6495a3, 0xa5e70de8, 
++    /*  16 */  0x0edb8832, 0x35581079, 0x79dcb8a4, 0x425f20ef, 
++    /*  20 */  0xe0d5e91e, 0xdb567155, 0x97d2d988, 0xac5141c3, 
++    /*  24 */  0x09b64c2b, 0x3235d460, 0x7eb17cbd, 0x4532e4f6, 
++    /*  28 */  0xe7b82d07, 0xdc3bb54c, 0x90bf1d91, 0xab3c85da, 
++    /*  32 */  0x1db71064, 0x2634882f, 0x6ab020f2, 0x5133b8b9, 
++    /*  36 */  0xf3b97148, 0xc83ae903, 0x84be41de, 0xbf3dd995, 
++    /*  40 */  0x1adad47d, 0x21594c36, 0x6ddde4eb, 0x565e7ca0, 
++    /*  44 */  0xf4d4b551, 0xcf572d1a, 0x83d385c7, 0xb8501d8c, 
++    /*  48 */  0x136c9856, 0x28ef001d, 0x646ba8c0, 0x5fe8308b, 
++    /*  52 */  0xfd62f97a, 0xc6e16131, 0x8a65c9ec, 0xb1e651a7, 
++    /*  56 */  0x14015c4f, 0x2f82c404, 0x63066cd9, 0x5885f492, 
++    /*  60 */  0xfa0f3d63, 0xc18ca528, 0x8d080df5, 0xb68b95be, 
++    /*  64 */  0x3b6e20c8, 0x00edb883, 0x4c69105e, 0x77ea8815, 
++    /*  68 */  0xd56041e4, 0xeee3d9af, 0xa2677172, 0x99e4e939, 
++    /*  72 */  0x3c03e4d1, 0x07807c9a, 0x4b04d447, 0x70874c0c, 
++    /*  76 */  0xd20d85fd, 0xe98e1db6, 0xa50ab56b, 0x9e892d20, 
++    /*  80 */  0x35b5a8fa, 0x0e3630b1, 0x42b2986c, 0x79310027, 
++    /*  84 */  0xdbbbc9d6, 0xe038519d, 0xacbcf940, 0x973f610b, 
++    /*  88 */  0x32d86ce3, 0x095bf4a8, 0x45df5c75, 0x7e5cc43e, 
++    /*  92 */  0xdcd60dcf, 0xe7559584, 0xabd13d59, 0x9052a512, 
++    /*  96 */  0x26d930ac, 0x1d5aa8e7, 0x51de003a, 0x6a5d9871, 
++    /* 100 */  0xc8d75180, 0xf354c9cb, 0xbfd06116, 0x8453f95d, 
++    /* 104 */  0x21b4f4b5, 0x1a376cfe, 0x56b3c423, 0x6d305c68, 
++    /* 108 */  0xcfba9599, 0xf4390dd2, 0xb8bda50f, 0x833e3d44, 
++    /* 112 */  0x2802b89e, 0x138120d5, 0x5f058808, 0x64861043, 
++    /* 116 */  0xc60cd9b2, 0xfd8f41f9, 0xb10be924, 0x8a88716f, 
++    /* 120 */  0x2f6f7c87, 0x14ece4cc, 0x58684c11, 0x63ebd45a, 
++    /* 124 */  0xc1611dab, 0xfae285e0, 0xb6662d3d, 0x8de5b576, 
++    /* 128 */  0x76dc4190, 0x4d5fd9db, 0x01db7106, 0x3a58e94d, 
++    /* 132 */  0x98d220bc, 0xa351b8f7, 0xefd5102a, 0xd4568861, 
++    /* 136 */  0x71b18589, 0x4a321dc2, 0x06b6b51f, 0x3d352d54, 
++    /* 140 */  0x9fbfe4a5, 0xa43c7cee, 0xe8b8d433, 0xd33b4c78, 
++    /* 144 */  0x7807c9a2, 0x438451e9, 0x0f00f934, 0x3483617f, 
++    /* 148 */  0x9609a88e, 0xad8a30c5, 0xe10e9818, 0xda8d0053, 
++    /* 152 */  0x7f6a0dbb, 0x44e995f0, 0x086d3d2d, 0x33eea566, 
++    /* 156 */  0x91646c97, 0xaae7f4dc, 0xe6635c01, 0xdde0c44a, 
++    /* 160 */  0x6b6b51f4, 0x50e8c9bf, 0x1c6c6162, 0x27eff929, 
++    /* 164 */  0x856530d8, 0xbee6a893, 0xf262004e, 0xc9e19805, 
++    /* 168 */  0x6c0695ed, 0x57850da6, 0x1b01a57b, 0x20823d30, 
++    /* 172 */  0x8208f4c1, 0xb98b6c8a, 0xf50fc457, 0xce8c5c1c, 
++    /* 176 */  0x65b0d9c6, 0x5e33418d, 0x12b7e950, 0x2934711b, 
++    /* 180 */  0x8bbeb8ea, 0xb03d20a1, 0xfcb9887c, 0xc73a1037, 
++    /* 184 */  0x62dd1ddf, 0x595e8594, 0x15da2d49, 0x2e59b502, 
++    /* 188 */  0x8cd37cf3, 0xb750e4b8, 0xfbd44c65, 0xc057d42e, 
++    /* 192 */  0x4db26158, 0x7631f913, 0x3ab551ce, 0x0136c985, 
++    /* 196 */  0xa3bc0074, 0x983f983f, 0xd4bb30e2, 0xef38a8a9, 
++    /* 200 */  0x4adfa541, 0x715c3d0a, 0x3dd895d7, 0x065b0d9c, 
++    /* 204 */  0xa4d1c46d, 0x9f525c26, 0xd3d6f4fb, 0xe8556cb0, 
++    /* 208 */  0x4369e96a, 0x78ea7121, 0x346ed9fc, 0x0fed41b7, 
++    /* 212 */  0xad678846, 0x96e4100d, 0xda60b8d0, 0xe1e3209b, 
++    /* 216 */  0x44042d73, 0x7f87b538, 0x33031de5, 0x088085ae, 
++    /* 220 */  0xaa0a4c5f, 0x9189d414, 0xdd0d7cc9, 0xe68ee482, 
++    /* 224 */  0x5005713c, 0x6b86e977, 0x270241aa, 0x1c81d9e1, 
++    /* 228 */  0xbe0b1010, 0x8588885b, 0xc90c2086, 0xf28fb8cd, 
++    /* 232 */  0x5768b525, 0x6ceb2d6e, 0x206f85b3, 0x1bec1df8, 
++    /* 236 */  0xb966d409, 0x82e54c42, 0xce61e49f, 0xf5e27cd4, 
++    /* 240 */  0x5edef90e, 0x655d6145, 0x29d9c998, 0x125a51d3, 
++    /* 244 */  0xb0d09822, 0x8b530069, 0xc7d7a8b4, 0xfc5430ff, 
++    /* 248 */  0x59b33d17, 0x6230a55c, 0x2eb40d81, 0x153795ca, 
++    /* 252 */  0xb7bd5c3b, 0x8c3ec470, 0xc0ba6cad, 0xfb39f4e6, 
++};
++
++unsigned int apc_crc32(const char* buf, int len)
++{
++    int i;
++    int k;
++    unsigned int crc;
++
++    /* preconditioning */
++    crc = 0xFFFFFFFF;
++    
++    for (i = 0; i < len; i++) {
++        k = (crc ^ buf[i]) & 0x000000FF;
++        crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[k];
++    }
++
++    /* postconditioning */
++    return ~crc;
++}
++
++/* crc32gen: generate the nth (0..255) crc32 table value */
++#if 0
++static unsigned long crc32gen(int n)
++{
++    int i;
++    unsigned long crc;
++    
++    crc = n;
++    for (i = 8; i >= 0; i--) {
++        if (crc & 1) {
++            crc = (crc >> 1) ^ 0xEDB88320;
++        }
++        else {
++            crc >>= 1;
++        }
++    }
++    return crc;
++}
++#endif
++
++/* }}} */
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_cache.c php-5.1.6/ext/APC/apc_cache.c
+--- php-5.1.6.old/ext/apc/apc_cache.c  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_cache.c      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,1328 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
++  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
++  +----------------------------------------------------------------------+
++
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
++
++   All other licensing and usage conditions are those of the PHP Group.
++
++ */
++
++/* $Id: apc_cache.c,v 3.140 2007/04/02 22:57:10 rasmus Exp $ */
++
++#include "apc_cache.h"
++#include "apc_lock.h"
++#include "apc_sma.h"
++#include "apc_globals.h"
++#include "SAPI.h"
++#include "ext/standard/php_var.h"
++#include "ext/standard/php_smart_str.h"
++
++/* TODO: rehash when load factor exceeds threshold */
++
++#define CHECK(p) { if ((p) == NULL) return NULL; }
++
++/* {{{ locking macros */
++#define CREATE_LOCK(lock)     apc_lck_create(NULL, 0, 1, lock)
++#define DESTROY_LOCK(c) apc_lck_destroy(c->header->lock)
++#define LOCK(c)         { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(c->header->lock); }
++#define RDLOCK(c)       { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(c->header->lock); }
++#define UNLOCK(c)       { apc_lck_unlock(c->header->lock); HANDLE_UNBLOCK_INTERRUPTIONS(); }
++/* }}} */
++
++/* {{{ struct definition: slot_t */
++typedef struct slot_t slot_t;
++struct slot_t {
++    apc_cache_key_t key;        /* slot key */
++    apc_cache_entry_t* value;   /* slot value */
++    slot_t* next;               /* next slot in linked list */
++    int num_hits;               /* number of hits to this bucket */
++    time_t creation_time;       /* time slot was initialized */
++    time_t deletion_time;       /* time slot was removed from cache */
++    time_t access_time;         /* time slot was last accessed */
++};
++/* }}} */
++
++/* {{{ struct definition: header_t
++   Any values that must be shared among processes should go in here. */
++typedef struct header_t header_t;
++struct header_t {
++    apc_lck_t lock;              /* read/write lock (exclusive blocking cache lock) */
++    apc_lck_t wrlock;           /* write lock (non-blocking used to prevent cache slams) */
++    int num_hits;               /* total successful hits in cache */
++    int num_misses;             /* total unsuccessful hits in cache */
++    int num_inserts;            /* total successful inserts in cache */
++    slot_t* deleted_list;       /* linked list of to-be-deleted slots */
++    time_t start_time;          /* time the above counters were reset */
++    int expunges;               /* total number of expunges */
++    zend_bool busy;             /* Flag to tell clients when we are busy cleaning the cache */
++    int num_entries;            /* Statistic on the number of entries */
++    size_t mem_size;            /* Statistic on the memory size used by this cache */
++};
++/* }}} */
++
++/* {{{ struct definition: apc_cache_t */
++struct apc_cache_t {
++    void* shmaddr;              /* process (local) address of shared cache */
++    header_t* header;           /* cache header (stored in SHM) */
++    slot_t** slots;             /* array of cache slots (stored in SHM) */
++    int num_slots;              /* number of slots in cache */
++    int gc_ttl;                 /* maximum time on GC list for a slot */
++    int ttl;                    /* if slot is needed and entry's access time is older than this ttl, remove it */
++};
++/* }}} */
++
++/* {{{ struct definition local_slot_t */
++typedef struct local_slot_t local_slot_t;
++struct local_slot_t {
++    slot_t *original;           /* the original slot in shm */
++    int num_hits;               /* number of hits */
++    apc_cache_entry_t *value;   /* shallow copy of slot->value */
++    local_slot_t *next;         /* only for dead list */
++};
++/* }}} */
++/* {{{ struct definition apc_local_cache_t */
++struct apc_local_cache_t {
++    apc_cache_t* shmcache;      /* the real cache in shm */
++    local_slot_t* slots;        /* process (local) cache of objects */
++    local_slot_t* dead_list;    /* list of objects pending removal */
++    int num_slots;              /* number of slots in cache */
++    int ttl;                    /* time to live */
++    int num_hits;               /* number of hits */
++    int generation;             /* every generation lives between expunges */
++};
++/* }}} */
++
++/* {{{ key_equals */
++#define key_equals(a, b) (a.inode==b.inode && a.device==b.device)
++/* }}} */
++
++/* {{{ hash */
++static unsigned int hash(apc_cache_key_t key)
++{
++    return key.data.file.device + key.data.file.inode;
++}
++/* }}} */
++
++/* {{{ string_nhash_8 */
++static unsigned int string_nhash_8(const char *s, size_t len)
++{
++    register const unsigned int *iv = (const unsigned int *)s;
++    register unsigned int h = 0;
++    register const unsigned int *e  = (const unsigned int *)(s + len - (len % sizeof(unsigned int)));
++
++    for(;iv<e;iv++) {
++        h += *iv;
++        h = (h << 7) | (h >> ((8*sizeof(unsigned int)) - 7));
++    }
++    s = (const char *)iv;
++    for(len %= sizeof(unsigned int);len;len--) {
++        h += *(s++);
++    }
++    h ^= (h >> 13);
++    h ^= (h >> 7);
++    return h;
++}
++/* }}} */
++
++/* {{{ make_slot */
++slot_t* make_slot(apc_cache_key_t key, apc_cache_entry_t* value, slot_t* next, time_t t)
++{
++    slot_t* p = apc_sma_malloc(sizeof(slot_t));
++    if (!p) return NULL;
++
++    if(value->type == APC_CACHE_ENTRY_USER) {
++        char *identifier = (char*) apc_xstrdup(key.data.user.identifier, apc_sma_malloc);
++        if (!identifier) {
++            apc_sma_free(p);
++            return NULL;
++        }
++        key.data.user.identifier = identifier;
++    } else if(key.type == APC_CACHE_KEY_FPFILE) {
++        char *fullpath = (char*) apc_xstrdup(key.data.fpfile.fullpath, apc_sma_malloc);
++        if (!fullpath) {
++            apc_sma_free(p);
++            return NULL;
++        }
++        key.data.fpfile.fullpath = fullpath;
++    }
++    p->key = key;
++    p->value = value;
++    p->next = next;
++    p->num_hits = 0;
++    p->creation_time = t;
++    p->access_time = t;
++    p->deletion_time = 0;
++    return p;
++}
++/* }}} */
++
++/* {{{ free_slot */
++static void free_slot(slot_t* slot)
++{
++    if(slot->value->type == APC_CACHE_ENTRY_USER) {
++        apc_sma_free((char *)slot->key.data.user.identifier);
++    } else if(slot->key.type == APC_CACHE_KEY_FPFILE) {
++        apc_sma_free((char *)slot->key.data.fpfile.fullpath);
++    }
++    apc_cache_free_entry(slot->value);
++    apc_sma_free(slot);
++}
++/* }}} */
++
++/* {{{ remove_slot */
++static void remove_slot(apc_cache_t* cache, slot_t** slot)
++{
++    slot_t* dead = *slot;
++    *slot = (*slot)->next;
++
++    cache->header->mem_size -= dead->value->mem_size;
++    cache->header->num_entries--;
++    if (dead->value->ref_count <= 0) {
++        free_slot(dead);
++    }
++    else {
++        dead->next = cache->header->deleted_list;
++        dead->deletion_time = time(0);
++        cache->header->deleted_list = dead;
++    }
++}
++/* }}} */
++
++/* {{{ process_pending_removals */
++static void process_pending_removals(apc_cache_t* cache)
++{
++    slot_t** slot;
++    time_t now;
++
++    /* This function scans the list of removed cache entries and deletes any
++     * entry whose reference count is zero (indicating that it is no longer
++     * being executed) or that has been on the pending list for more than
++     * cache->gc_ttl seconds (we issue a warning in the latter case).
++     */
++
++    if (!cache->header->deleted_list)
++        return;
++
++    slot = &cache->header->deleted_list;
++    now = time(0);
++
++    while (*slot != NULL) {
++        int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0;
++
++        if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) {
++            slot_t* dead = *slot;
++
++            if (dead->value->ref_count > 0) {
++                switch(dead->value->type) {
++                    case APC_CACHE_ENTRY_FILE:
++                        apc_log(APC_WARNING, "GC cache entry '%s' (dev=%d ino=%d) "
++                            "was on gc-list for %d seconds", dead->value->data.file.filename,
++                            dead->key.data.file.device, dead->key.data.file.inode, gc_sec);
++                        break;
++                    case APC_CACHE_ENTRY_USER:
++                        apc_log(APC_WARNING, "GC cache entry '%s' "
++                            "was on gc-list for %d seconds", dead->value->data.user.info, gc_sec);
++                        break;
++                }
++            }
++            *slot = dead->next;
++            free_slot(dead);
++        }
++        else {
++            slot = &(*slot)->next;
++        }
++    }
++}
++/* }}} */
++
++/* {{{ prevent_garbage_collection */
++static void prevent_garbage_collection(apc_cache_entry_t* entry)
++{
++    /* set reference counts on zend objects to an arbitrarily high value to
++     * prevent garbage collection after execution */
++
++    enum { BIG_VALUE = 1000 };
++
++    if(entry->data.file.op_array) {
++        entry->data.file.op_array->refcount[0] = BIG_VALUE;
++    }
++    if (entry->data.file.functions) {
++        int i;
++        apc_function_t* fns = entry->data.file.functions;
++        for (i=0; fns[i].function != NULL; i++) {
++#ifdef ZEND_ENGINE_2            
++            *(fns[i].function->op_array.refcount) = BIG_VALUE;
++#else            
++            fns[i].function->op_array.refcount[0] = BIG_VALUE;
++#endif            
++        }
++    }
++    if (entry->data.file.classes) {
++        int i;
++        apc_class_t* classes = entry->data.file.classes;
++        for (i=0; classes[i].class_entry != NULL; i++) {
++#ifdef ZEND_ENGINE_2            
++            classes[i].class_entry->refcount = BIG_VALUE;
++#else            
++            classes[i].class_entry->refcount[0] = BIG_VALUE;
++#endif
++        }
++    }
++}
++/* }}} */
++
++/* {{{ apc_cache_create */
++apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl)
++{
++    apc_cache_t* cache;
++    int cache_size;
++    int num_slots;
++    int i;
++
++    num_slots = size_hint > 0 ? size_hint*2 : 2000;
++
++    cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t));
++    cache_size = sizeof(header_t) + num_slots*sizeof(slot_t*);
++
++    cache->shmaddr = apc_sma_malloc(cache_size);
++    memset(cache->shmaddr, 0, cache_size);
++
++    cache->header = (header_t*) cache->shmaddr;
++    cache->header->num_hits = 0;
++    cache->header->num_misses = 0;
++    cache->header->deleted_list = NULL;
++    cache->header->start_time = time(NULL);
++    cache->header->expunges = 0;
++    cache->header->busy = 0;
++
++    cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(header_t));
++    cache->num_slots = num_slots;
++    cache->gc_ttl = gc_ttl;
++    cache->ttl = ttl;
++    CREATE_LOCK(cache->header->lock);
++#if NONBLOCKING_LOCK_AVAILABLE
++    CREATE_LOCK(cache->header->wrlock);
++#endif
++    for (i = 0; i < num_slots; i++) {
++        cache->slots[i] = NULL;
++    }
++
++    return cache;
++}
++/* }}} */
++
++/* {{{ apc_cache_destroy */
++void apc_cache_destroy(apc_cache_t* cache)
++{
++    DESTROY_LOCK(cache);
++    apc_efree(cache);
++}
++/* }}} */
++
++/* {{{ apc_cache_clear */
++void apc_cache_clear(apc_cache_t* cache)
++{
++    int i;
++
++    if(!cache) return;
++
++    LOCK(cache);
++    cache->header->busy = 1;
++    cache->header->num_hits = 0;
++    cache->header->num_misses = 0;
++    cache->header->start_time = time(NULL);
++    cache->header->expunges = 0;
++
++    for (i = 0; i < cache->num_slots; i++) {
++        slot_t* p = cache->slots[i];
++        while (p) {
++            remove_slot(cache, &p);
++        }
++        cache->slots[i] = NULL;
++    }
++    
++    cache->header->busy = 0;
++    UNLOCK(cache);
++}
++/* }}} */
++
++/* {{{ apc_cache_expunge */
++void apc_cache_expunge(apc_cache_t* cache, time_t t)
++{
++    int i;
++
++    if(!cache) return;
++
++    if(!cache->ttl) {
++        /* 
++         * If cache->ttl is not set, we wipe out the entire cache when
++         * we run out of space. 
++         */
++        LOCK(cache);
++        cache->header->busy = 1;
++        cache->header->expunges++;
++        for (i = 0; i < cache->num_slots; i++) {
++            slot_t* p = cache->slots[i];
++            while (p) {
++                remove_slot(cache, &p);
++            }
++            cache->slots[i] = NULL;
++        }
++        cache->header->busy = 0;
++        UNLOCK(cache);
++    } else {
++        slot_t **p;
++
++        /*
++         * If the ttl for the cache is set we walk through and delete stale 
++         * entries.  For the user cache that is slightly confusing since
++         * we have the individual entry ttl's we can look at, but that would be
++         * too much work.  So if you want the user cache expunged, set a high
++         * default apc.user_ttl and still provide a specific ttl for each entry
++         * on insert
++         */
++
++        LOCK(cache);
++        cache->header->busy = 1;
++        cache->header->expunges++;
++        for (i = 0; i < cache->num_slots; i++) {
++            p = &cache->slots[i];
++            while(*p) {
++                /* 
++                 * For the user cache we look at the individual entry ttl values
++                 * and if not set fall back to the default ttl for the user cache
++                 */
++                if((*p)->value->type == APC_CACHE_ENTRY_USER) {
++                    if((*p)->value->data.user.ttl) {
++                        if((*p)->creation_time + (*p)->value->data.user.ttl < t) {
++                            remove_slot(cache, p);
++                            continue;
++                        }
++                    } else if(cache->ttl) {
++                        if((*p)->creation_time + cache->ttl < t) {
++                            remove_slot(cache, p);
++                            continue;
++                        }
++                    }
++                } else if((*p)->access_time < (t - cache->ttl)) {
++                    remove_slot(cache, p);
++                    continue;
++                }
++                p = &(*p)->next;
++            }
++        }
++        cache->header->busy = 0;
++        UNLOCK(cache);
++    }
++}
++/* }}} */
++
++/* {{{ apc_cache_insert */
++int apc_cache_insert(apc_cache_t* cache,
++                     apc_cache_key_t key,
++                     apc_cache_entry_t* value,
++                     time_t t)
++{
++    slot_t** slot;
++
++    if (!value) {
++        return 0;
++    }
++
++#ifdef __DEBUG_APC__
++    fprintf(stderr,"Inserting [%s]\n", value->data.file.filename);
++#endif
++
++    LOCK(cache);
++    process_pending_removals(cache);
++
++    if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
++    else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
++
++    while(*slot) {
++      if(key.type == (*slot)->key.type) {
++        if(key.type == APC_CACHE_KEY_FILE) {
++            if(key_equals((*slot)->key.data.file, key.data.file)) {
++                /* If existing slot for the same device+inode is different, remove it and insert the new version */
++                if ((*slot)->key.mtime != key.mtime) {
++                    remove_slot(cache, slot);
++                    break;
++                }
++                UNLOCK(cache);
++                return 0;
++            } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
++                remove_slot(cache, slot);
++                continue;
++            }
++        } else {   /* APC_CACHE_KEY_FPFILE */
++                if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
++                /* Hrm.. it's already here, remove it and insert new one */
++                remove_slot(cache, slot);
++                break;
++            } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
++                remove_slot(cache, slot);
++                continue;
++            }
++        }
++      }
++      slot = &(*slot)->next;
++    }
++
++    if ((*slot = make_slot(key, value, *slot, t)) == NULL) {
++        UNLOCK(cache);
++        return -1;
++    }
++   
++    cache->header->mem_size += value->mem_size;
++    cache->header->num_entries++;
++    cache->header->num_inserts++;
++    
++    UNLOCK(cache);
++    return 1;
++}
++/* }}} */
++
++/* {{{ apc_cache_user_insert */
++int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, time_t t, int exclusive TSRMLS_DC)
++{
++    slot_t** slot;
++    size_t* mem_size_ptr = NULL;
++
++    if (!value) {
++        return 0;
++    }
++
++    LOCK(cache);
++    process_pending_removals(cache);
++
++    slot = &cache->slots[string_nhash_8(key.data.user.identifier, key.data.user.identifier_len) % cache->num_slots];
++
++    if (APCG(mem_size_ptr) != NULL) {
++        mem_size_ptr = APCG(mem_size_ptr);
++        APCG(mem_size_ptr) = NULL;
++    }
++
++    while (*slot) {
++        if (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, key.data.user.identifier_len)) {
++            /* 
++             * At this point we have found the user cache entry.  If we are doing 
++             * an exclusive insert (apc_add) we are going to bail right away if
++             * the user entry already exists and it has no ttl, or
++             * there is a ttl and the entry has not timed out yet.
++             */
++            if(exclusive && (  !(*slot)->value->data.user.ttl ||
++                              ( (*slot)->value->data.user.ttl && ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t ) 
++                            ) ) {
++                UNLOCK(cache);
++                return 0;
++            }
++            remove_slot(cache, slot);
++            break;
++        } else 
++        /* 
++         * This is a bit nasty.  The idea here is to do runtime cleanup of the linked list of
++         * slot entries so we don't always have to skip past a bunch of stale entries.  We check
++         * for staleness here and get rid of them by first checking to see if the cache has a global
++         * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly
++         * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl
++         */
++        if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) || 
++           ((*slot)->value->data.user.ttl && ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) {
++            remove_slot(cache, slot);
++            continue;
++        }
++        slot = &(*slot)->next;
++    }
++
++    if (mem_size_ptr != NULL) {
++        APCG(mem_size_ptr) = mem_size_ptr;
++    }
++
++    if ((*slot = make_slot(key, value, *slot, t)) == NULL) {
++        UNLOCK(cache);
++        return 0;
++    }
++    if (APCG(mem_size_ptr) != NULL) {
++        value->mem_size = *APCG(mem_size_ptr);
++        cache->header->mem_size += *APCG(mem_size_ptr);
++    }
++    cache->header->num_entries++;
++    cache->header->num_inserts++;
++
++    UNLOCK(cache);
++    return 1;
++}
++/* }}} */
++
++/* {{{ apc_cache_find_slot */
++slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t)
++{
++    slot_t** slot;
++    volatile slot_t* retval = NULL;
++
++    LOCK(cache);
++    if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
++    else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
++
++    while (*slot) {
++      if(key.type == (*slot)->key.type) {
++        if(key.type == APC_CACHE_KEY_FILE) {
++            if(key_equals((*slot)->key.data.file, key.data.file)) {
++                if((*slot)->key.mtime != key.mtime) {
++                    remove_slot(cache, slot);
++                    cache->header->num_misses++;
++                    UNLOCK(cache);
++                    return NULL;
++                }
++                (*slot)->num_hits++;
++                (*slot)->value->ref_count++;
++                (*slot)->access_time = t;
++                prevent_garbage_collection((*slot)->value);
++                cache->header->num_hits++;
++                retval = *slot;
++                UNLOCK(cache);
++                return (slot_t*)retval;
++            }
++        } else {  /* APC_CACHE_KEY_FPFILE */
++            if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
++                /* TTL Check ? */
++                (*slot)->num_hits++;
++                (*slot)->value->ref_count++;
++                (*slot)->access_time = t;
++                prevent_garbage_collection((*slot)->value);
++                cache->header->num_hits++;
++                retval = *slot;
++                UNLOCK(cache);
++                return (slot_t*)retval;
++            }
++        }
++      }
++      slot = &(*slot)->next;
++    }
++    cache->header->num_misses++;
++    UNLOCK(cache);
++    return NULL;
++}
++/* }}} */
++
++/* {{{ apc_cache_find */
++apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t)
++{
++    slot_t * slot = apc_cache_find_slot(cache, key, t);
++    return (slot) ? slot->value : NULL;
++}
++/* }}} */
++
++/* {{{ apc_cache_user_find */
++apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t)
++{
++    slot_t** slot;
++    volatile apc_cache_entry_t* value = NULL;
++
++    LOCK(cache);
++
++    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
++
++    while (*slot) {
++        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
++            /* Check to make sure this entry isn't expired by a hard TTL */
++            if((*slot)->value->data.user.ttl && ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
++                remove_slot(cache, slot);
++                UNLOCK(cache);
++                return NULL;
++            }
++            /* Otherwise we are fine, increase counters and return the cache entry */
++            (*slot)->num_hits++;
++            (*slot)->value->ref_count++;
++            (*slot)->access_time = t;
++
++            cache->header->num_hits++;
++            value = (*slot)->value;
++            UNLOCK(cache);
++            return (apc_cache_entry_t*)value;
++        }
++        slot = &(*slot)->next;
++    }
++ 
++    UNLOCK(cache);
++    return NULL;
++}
++/* }}} */
++
++/* {{{ apc_cache_user_delete */
++int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen)
++{
++    slot_t** slot;
++
++    LOCK(cache);
++
++    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
++
++    while (*slot) {
++        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
++            remove_slot(cache, slot);
++            UNLOCK(cache);
++            return 1;
++        }
++        slot = &(*slot)->next;
++    }
++
++    UNLOCK(cache);
++    return 0;
++}
++/* }}} */
++
++/* {{{ apc_cache_release */
++void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry)
++{
++    /* local cache refcount-- is done in apc_local_cache_cleanup */
++    if(entry->local) return;
++
++    LOCK(cache);
++    entry->ref_count--;
++    UNLOCK(cache);
++}
++/* }}} */
++
++/* {{{ apc_cache_make_file_key */
++int apc_cache_make_file_key(apc_cache_key_t* key,
++                       const char* filename,
++                       const char* include_path,
++                       time_t t
++                                         TSRMLS_DC)
++{
++    static char canon_path[MAXPATHLEN];
++    struct stat *tmp_buf=NULL;
++    struct apc_fileinfo_t fileinfo = { {0}, };
++    int len;
++      
++    assert(key != NULL);
++
++    if (!filename || !SG(request_info).path_translated) {
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"No filename and no path_translated - bailing\n");
++#endif
++        return 0;
++      }
++
++    len = strlen(filename);
++    if(APCG(fpstat)==0) {
++        if(IS_ABSOLUTE_PATH(filename,len)) {
++            key->data.fpfile.fullpath = filename;
++            key->data.fpfile.fullpath_len = len;
++            key->mtime = t;
++            key->type = APC_CACHE_KEY_FPFILE;
++        } else {
++            if(!realpath(filename, canon_path)) {
++                fprintf(stderr, "realpath failed to canonicalize %s - bailing\n", filename);
++                return 0;
++            }
++            key->data.fpfile.fullpath = canon_path;
++            key->data.fpfile.fullpath_len = strlen(canon_path);
++            key->mtime = t;
++            key->type = APC_CACHE_KEY_FPFILE;
++        }
++        return 1;
++    } 
++
++    if(!strcmp(SG(request_info).path_translated, filename)) {
++        tmp_buf = sapi_get_stat(TSRMLS_C);  /* Apache has already done this stat() for us */
++    }
++    if(tmp_buf) { 
++              fileinfo.st_buf = *tmp_buf;
++    } else {
++        if (apc_search_paths(filename, include_path, &fileinfo) != 0) {
++#ifdef __DEBUG_APC__
++            fprintf(stderr,"Stat failed %s - bailing (%s) (%d)\n",filename,SG(request_info).path_translated);
++#endif
++            return 0;
++        }
++    }
++
++    if(APCG(max_file_size) < fileinfo.st_buf.st_size) {
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"File is too big %s (%d - %ld) - bailing\n",filename,t,fileinfo.st_buf.st_size);
++#endif
++        return 0;
++    }
++
++    /*
++     * This is a bit of a hack.
++     *
++     * Here I am checking to see if the file is at least 2 seconds old.  
++     * The idea is that if the file is currently being written to then its
++     * mtime is going to match or at most be 1 second off of the current
++     * request time and we want to avoid caching files that have not been
++     * completely written.  Of course, people should be using atomic 
++     * mechanisms to push files onto live web servers, but adding this
++     * tiny safety is easier than educating the world.  This is now
++     * configurable, but the default is still 2 seconds.
++     */
++    if(APCG(file_update_protection) && (t - fileinfo.st_buf.st_mtime < APCG(file_update_protection))) { 
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"File is too new %s (%d - %d) - bailing\n",filename,t,fileinfo.st_buf.st_mtime);
++#endif
++        return 0;
++    }
++
++    key->data.file.device = fileinfo.st_buf.st_dev;
++    key->data.file.inode  = fileinfo.st_buf.st_ino;
++    /* 
++     * If working with content management systems that like to munge the mtime, 
++     * it might be appropriate to key off of the ctime to be immune to systems
++     * that try to backdate a template.  If the mtime is set to something older
++     * than the previous mtime of a template we will obviously never see this
++     * "older" template.  At some point the Smarty templating system did this.
++     * I generally disagree with using the ctime here because you lose the 
++     * ability to warm up new content by saving it to a temporary file, hitting
++     * it once to cache it and then renaming it into its permanent location so
++     * set the apc.stat_ctime=true to enable this check.
++     */
++    if(APCG(stat_ctime)) {
++        key->mtime  = (fileinfo.st_buf.st_ctime > fileinfo.st_buf.st_mtime) ? fileinfo.st_buf.st_ctime : fileinfo.st_buf.st_mtime; 
++    } else {
++        key->mtime = fileinfo.st_buf.st_mtime;
++    }
++    key->type = APC_CACHE_KEY_FILE;
++    return 1;
++}
++/* }}} */
++
++/* {{{ apc_cache_make_user_key */
++int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t)
++{
++    assert(key != NULL);
++
++    if (!identifier)
++        return 0;
++
++    key->data.user.identifier = identifier;
++    key->data.user.identifier_len = identifier_len;
++    key->mtime = t;
++    key->type = APC_CACHE_KEY_USER;
++    return 1;
++}
++/* }}} */
++
++/* {{{ apc_cache_make_file_entry */
++apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
++                                        zend_op_array* op_array,
++                                        apc_function_t* functions,
++                                        apc_class_t* classes)
++{
++    apc_cache_entry_t* entry;
++
++    entry = (apc_cache_entry_t*) apc_sma_malloc(sizeof(apc_cache_entry_t));
++    if (!entry) return NULL;
++
++    entry->data.file.filename  = apc_xstrdup(filename, apc_sma_malloc);
++    if(!entry->data.file.filename) {
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n");
++#endif
++        apc_sma_free(entry);
++        return NULL;
++    }
++#ifdef __DEBUG_APC__
++    fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is [%s]\n",entry->data.file.filename);
++#endif
++    entry->data.file.op_array  = op_array;
++    entry->data.file.functions = functions;
++    entry->data.file.classes   = classes;
++    entry->type = APC_CACHE_ENTRY_FILE;
++    entry->ref_count = 0;
++    entry->mem_size = 0;
++    entry->autofiltered = 0;
++    entry->local = 0;
++    return entry;
++}
++/* }}} */
++
++/* {{{ apc_cache_store_zval */
++zval* apc_cache_store_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    smart_str buf = {0};
++    php_serialize_data_t var_hash;
++    TSRMLS_FETCH();
++
++    if((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) {
++        if(!dst) {
++            CHECK(dst = (zval*) allocate(sizeof(zval)));
++        }
++              
++        PHP_VAR_SERIALIZE_INIT(var_hash);
++        php_var_serialize(&buf, (zval**)&src, &var_hash TSRMLS_CC);
++        PHP_VAR_SERIALIZE_DESTROY(var_hash);
++              
++        dst->type = IS_NULL; /* in case we fail */
++        if(buf.c) {
++            dst->type = src->type & ~IS_CONSTANT_INDEX;
++            dst->value.str.len = buf.len;
++            CHECK(dst->value.str.val = apc_xmemcpy(buf.c, buf.len+1, allocate));
++            dst->type = src->type;
++            smart_str_free(&buf);
++        }
++        return dst; 
++    } else {
++        
++        /* Maintain a list of zvals we've copied to properly handle recursive structures */
++        HashTable *old = APCG(copied_zvals);
++        APCG(copied_zvals) = emalloc(sizeof(HashTable));
++        zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0);
++        
++        dst = apc_copy_zval(dst, src, allocate, deallocate);
++
++        if(APCG(copied_zvals)) {
++            zend_hash_destroy(APCG(copied_zvals));
++            efree(APCG(copied_zvals));
++        }
++
++        APCG(copied_zvals) = old;
++
++        return dst;
++    }
++}
++/* }}} */
++
++/* {{{ apc_cache_fetch_zval */
++zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    TSRMLS_FETCH();
++    if((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) {
++        php_unserialize_data_t var_hash;
++        const unsigned char *p = (unsigned char*)Z_STRVAL_P(src);
++
++        PHP_VAR_UNSERIALIZE_INIT(var_hash);
++        if(!php_var_unserialize(&dst, &p, p + Z_STRLEN_P(src), &var_hash TSRMLS_CC)) {
++            PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
++            zval_dtor(dst);
++            php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - Z_STRVAL_P(src)), Z_STRLEN_P(src));
++            dst->type = IS_NULL;
++        }
++        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);                
++        return dst; 
++    } else {
++    
++        /* Maintain a list of zvals we've copied to properly handle recursive structures */
++        HashTable *old = APCG(copied_zvals);
++        APCG(copied_zvals) = emalloc(sizeof(HashTable));
++        zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0);
++        
++        dst = apc_copy_zval(dst, src, allocate, deallocate);
++
++        if(APCG(copied_zvals)) {
++            zend_hash_destroy(APCG(copied_zvals));
++            efree(APCG(copied_zvals));
++        }
++
++        APCG(copied_zvals) = old;
++
++        return dst;
++    }
++}
++/* }}} */
++
++/* {{{ apc_cache_free_zval */
++void apc_cache_free_zval(zval* src, apc_free_t deallocate)
++{
++    TSRMLS_FETCH();
++    if ((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) {
++        if (src->value.str.val) {
++              deallocate(src->value.str.val);
++        }
++        deallocate(src);
++    } else {
++        /* Maintain a list of zvals we've copied to properly handle recursive structures */
++        HashTable *old = APCG(copied_zvals);
++        APCG(copied_zvals) = emalloc(sizeof(HashTable));
++        zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0);
++        
++        apc_free_zval(src, deallocate);
++
++        if(APCG(copied_zvals)) {
++            zend_hash_destroy(APCG(copied_zvals));
++            efree(APCG(copied_zvals));
++        }
++
++        APCG(copied_zvals) = old;
++    }
++}
++/* }}} */
++
++/* {{{ apc_cache_make_user_entry */
++apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, const unsigned int ttl)
++{
++    apc_cache_entry_t* entry;
++
++    entry = (apc_cache_entry_t*) apc_sma_malloc(sizeof(apc_cache_entry_t));
++    if (!entry) return NULL;
++
++    entry->data.user.info = apc_xmemcpy(info, info_len, apc_sma_malloc);
++    entry->data.user.info_len = info_len;
++    if(!entry->data.user.info) {
++        apc_sma_free(entry);
++        return NULL;
++    }
++    entry->data.user.val = apc_cache_store_zval(NULL, val, apc_sma_malloc, apc_sma_free);
++    if(!entry->data.user.val) {
++        apc_sma_free(entry->data.user.info);
++        apc_sma_free(entry);
++        return NULL;
++    }
++    INIT_PZVAL(entry->data.user.val);
++    entry->data.user.ttl = ttl;
++    entry->type = APC_CACHE_ENTRY_USER;
++    entry->ref_count = 0;
++    entry->mem_size = 0;
++    entry->autofiltered = 0;
++    entry->local = 0;
++    return entry;
++}
++/* }}} */
++
++/* {{{ apc_cache_free_entry */
++void apc_cache_free_entry(apc_cache_entry_t* entry)
++{
++    if (entry != NULL) {
++        assert(entry->ref_count == 0);
++        switch(entry->type) {
++            case APC_CACHE_ENTRY_FILE:
++                apc_sma_free(entry->data.file.filename);
++                apc_free_op_array(entry->data.file.op_array, apc_sma_free);
++                apc_free_functions(entry->data.file.functions, apc_sma_free);
++                apc_free_classes(entry->data.file.classes, apc_sma_free);
++                break;
++            case APC_CACHE_ENTRY_USER:
++                apc_sma_free(entry->data.user.info);
++                apc_cache_free_zval(entry->data.user.val, apc_sma_free);
++                break;
++        }
++        apc_sma_free(entry);
++    }
++}
++/* }}} */
++
++/* {{{ apc_cache_info */
++apc_cache_info_t* apc_cache_info(apc_cache_t* cache, zend_bool limited)
++{
++    apc_cache_info_t* info;
++    slot_t* p;
++    int i;
++
++    if(!cache) return NULL;
++
++    LOCK(cache);
++
++    info = (apc_cache_info_t*) apc_emalloc(sizeof(apc_cache_info_t));
++    if(!info) {
++        UNLOCK(cache);
++        return NULL;
++    }
++    info->num_slots = cache->num_slots;
++    info->ttl = cache->ttl;
++    info->num_hits = cache->header->num_hits;
++    info->num_misses = cache->header->num_misses;
++    info->list = NULL;
++    info->deleted_list = NULL;
++    info->start_time = cache->header->start_time;
++    info->expunges = cache->header->expunges;
++    info->mem_size = cache->header->mem_size;
++    info->num_entries = cache->header->num_entries;
++    info->num_inserts = cache->header->num_inserts;
++
++    if(!limited) {
++        /* For each hashtable slot */
++        for (i = 0; i < info->num_slots; i++) {
++            p = cache->slots[i];
++            for (; p != NULL; p = p->next) {
++                apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t));
++
++                if(p->value->type == APC_CACHE_ENTRY_FILE) {
++                    link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc);
++                    link->data.file.device = p->key.data.file.device;
++                    link->data.file.inode = p->key.data.file.inode;
++                    link->type = APC_CACHE_ENTRY_FILE;
++                } else if(p->value->type == APC_CACHE_ENTRY_USER) {
++                    link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len, apc_emalloc);
++                    link->data.user.ttl = p->value->data.user.ttl;
++                    link->type = APC_CACHE_ENTRY_USER;
++                }
++                link->num_hits = p->num_hits;
++                link->mtime = p->key.mtime;
++                link->creation_time = p->creation_time;
++                link->deletion_time = p->deletion_time;
++                link->access_time = p->access_time;
++                link->ref_count = p->value->ref_count;
++                link->mem_size = p->value->mem_size;
++                link->next = info->list;
++                info->list = link;
++            }
++        }
++
++        /* For each slot pending deletion */
++        for (p = cache->header->deleted_list; p != NULL; p = p->next) {
++            apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t));
++
++            if(p->value->type == APC_CACHE_ENTRY_FILE) {
++                link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc);
++                if(p->key.type == APC_CACHE_KEY_FILE) {
++                    link->data.file.device = p->key.data.file.device;
++                    link->data.file.inode = p->key.data.file.inode;
++                } else { /* This is a no-stat fullpath file entry */
++                    link->data.file.device = 0;
++                    link->data.file.inode = 0;
++                }
++                link->type = APC_CACHE_ENTRY_FILE;
++            } else if(p->value->type == APC_CACHE_ENTRY_USER) {
++                link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len, apc_emalloc);
++                link->data.user.ttl = p->value->data.user.ttl;
++                link->type = APC_CACHE_ENTRY_USER;
++            }
++            link->num_hits = p->num_hits;
++            link->mtime = p->key.mtime;
++            link->creation_time = p->creation_time;
++            link->deletion_time = p->deletion_time;
++            link->access_time = p->access_time;
++            link->ref_count = p->value->ref_count;
++            link->mem_size = p->value->mem_size;
++            link->next = info->deleted_list;
++            info->deleted_list = link;
++        }
++    }
++
++    UNLOCK(cache);
++    return info;
++}
++/* }}} */
++
++/* {{{ apc_cache_free_info */
++void apc_cache_free_info(apc_cache_info_t* info)
++{
++    apc_cache_link_t* p = info->list;
++    apc_cache_link_t* q = NULL;
++    while (p != NULL) {
++        q = p;
++        p = p->next;
++        if(q->type == APC_CACHE_ENTRY_FILE) apc_efree(q->data.file.filename);
++        else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info);
++        apc_efree(q);
++    }
++    p = info->deleted_list;
++    while (p != NULL) {
++        q = p;
++        p = p->next;
++        if(q->type == APC_CACHE_ENTRY_FILE) apc_efree(q->data.file.filename);
++        else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info);
++        apc_efree(q);
++    }
++    apc_efree(info);
++}
++/* }}} */
++
++/* {{{ apc_cache_unlock */
++void apc_cache_unlock(apc_cache_t* cache)
++{
++    UNLOCK(cache);
++}
++/* }}} */
++
++/* {{{ apc_cache_busy */
++zend_bool apc_cache_busy(apc_cache_t* cache)
++{
++    return cache->header->busy;
++}
++/* }}} */
++
++#if NONBLOCKING_LOCK_AVAILABLE
++/* {{{ apc_cache_write_lock */
++zend_bool apc_cache_write_lock(apc_cache_t* cache)
++{
++    return apc_lck_nb_lock(cache->header->wrlock);
++}
++/* }}} */
++
++/* {{{ apc_cache_write_unlock */
++void apc_cache_write_unlock(apc_cache_t* cache)
++{
++    apc_lck_unlock(cache->header->wrlock);
++}
++/* }}} */
++#endif
++
++/* {{{ make_local_slot */
++static local_slot_t* make_local_slot(apc_local_cache_t* cache, local_slot_t* lslot, slot_t* slot) 
++{
++    apc_cache_entry_t* value;
++
++    value = apc_emalloc(sizeof(apc_cache_entry_t));
++    memcpy(value, slot->value, sizeof(apc_cache_entry_t)); /* bitwise copy */
++    value->local = 1;
++
++    lslot->original = slot;
++    lslot->value = value;
++    lslot->num_hits++;
++
++    return lslot; /* for what joy ? ... consistency */
++}
++/* }}} */
++
++/* {{{ free_local_slot */
++static void free_local_slot(apc_local_cache_t* cache, local_slot_t* lslot) 
++{
++    local_slot_t * dead = NULL;
++    if(!lslot->original) return;
++
++    /* TODO: Bad design to allocate memory in a free_* - fix when bored (hehe) */
++    dead = apc_emalloc(sizeof(local_slot_t));
++    memcpy(dead, lslot, sizeof(local_slot_t)); /* bitwise copy */
++
++    lslot->original = NULL;
++    lslot->value = NULL;
++
++    dead->next = cache->dead_list;
++    cache->dead_list = dead;
++}
++/* }}} */
++
++/* {{{ apc_local_cache_create */
++apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl)
++{
++    apc_local_cache_t* cache = NULL;
++
++    cache = (apc_local_cache_t*) apc_emalloc(sizeof(apc_local_cache_t));
++
++    cache->slots = (local_slot_t*) (apc_emalloc(sizeof(local_slot_t) * num_slots));
++    memset(cache->slots, 0, sizeof(local_slot_t) * num_slots);
++
++    cache->shmcache = shmcache;
++    cache->num_slots = num_slots;
++    cache->ttl = ttl;
++    cache->num_hits = 0;
++    cache->generation = shmcache->header->expunges;
++    cache->dead_list = NULL;
++
++    return cache;
++}
++/* }}} */
++
++/* {{{ apc_local_cache_cleanup */
++void apc_local_cache_cleanup(apc_local_cache_t* cache) {
++    local_slot_t * lslot;
++    time_t t = time(0);
++    
++    int i;
++    for(i = 0; i < cache->num_slots; i++) {
++        slot_t * slot = cache->slots[i].original;
++        if((slot && slot->access_time < (t - cache->ttl)) ||
++                cache->generation != cache->shmcache->header->expunges) {
++            free_local_slot(cache, &cache->slots[i]);
++        }
++    }
++
++    LOCK(cache->shmcache);
++    for(lslot = cache->dead_list; lslot != NULL; lslot = lslot->next) {
++        lslot->original->num_hits += lslot->num_hits;
++        lslot->original->value->ref_count--; /* apc_cache_release(cache->shmcache, lslot->original->value); */
++        apc_efree(lslot->value);
++    }
++    UNLOCK(cache->shmcache);
++
++    cache->dead_list = NULL;
++}
++/* }}} */
++
++/* {{{ apc_local_cache_destroy */
++void apc_local_cache_destroy(apc_local_cache_t* cache)
++{
++    int i;
++    for(i = 0; i < cache->num_slots; i++) {
++        free_local_slot(cache, &cache->slots[i]);
++    }
++
++    apc_local_cache_cleanup(cache);
++
++    LOCK(cache->shmcache);
++    cache->shmcache->header->num_hits += cache->num_hits;
++    UNLOCK(cache->shmcache);
++
++    apc_efree(cache->slots);
++    apc_efree(cache);
++}
++/* }}} */
++
++/* {{{ apc_local_cache_find */
++apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t)
++{
++    slot_t* slot;
++    local_slot_t* lslot; 
++
++    if(key.type == APC_CACHE_KEY_FILE) lslot = &cache->slots[hash(key) % cache->num_slots];
++    else lslot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
++
++    slot = lslot->original;
++
++    if(slot && key.type == slot->key.type) {
++        if(slot->access_time < (t - cache->ttl)) {
++            goto not_found;
++        }
++        if(key.type == APC_CACHE_KEY_FILE && 
++           key_equals(slot->key.data.file, key.data.file)) {
++            if(slot->key.mtime != key.mtime) {
++                free_local_slot(cache, lslot);
++                goto not_found;
++            }
++            return lslot->value;
++        } else if(key.type == APC_CACHE_KEY_FPFILE) {
++            if(!memcmp(slot->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
++                return lslot->value;
++            }
++        }
++    }
++not_found:
++    if(apc_cache_busy(cache->shmcache)) {
++        return NULL;
++    }
++
++    slot = apc_cache_find_slot(cache->shmcache, key, t);
++
++    if(!slot) return NULL;
++   
++    /* i.e maintain a sort of top list */
++    if(lslot->original == NULL || (lslot->original->num_hits + lslot->num_hits)  < slot->num_hits) {
++        free_local_slot(cache, lslot);
++        make_local_slot(cache, lslot, slot); 
++        return lslot->value;
++    }
++    return slot->value;
++}
++/* }}} */
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_cache.h php-5.1.6/ext/APC/apc_cache.h
+--- php-5.1.6.old/ext/apc/apc_cache.h  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_cache.h      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,313 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt.                                 |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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_cache.h,v 3.45 2007/03/22 16:03:59 gopalv Exp $ */
++
++#ifndef APC_CACHE_H
++#define APC_CACHE_H
++
++/*
++ * This module defines the shared memory file cache. Basically all of the
++ * logic for storing and retrieving cache entries lives here.
++ */
++
++#include "apc.h"
++#include "apc_compile.h"
++
++#define APC_CACHE_ENTRY_FILE   1
++#define APC_CACHE_ENTRY_USER   2
++
++#define APC_CACHE_KEY_FILE     1
++#define APC_CACHE_KEY_USER     2
++#define APC_CACHE_KEY_FPFILE   3
++
++/* {{{ struct definition: apc_cache_key_t */
++#define T apc_cache_t*
++typedef struct apc_cache_t apc_cache_t; /* opaque cache type */
++
++typedef union _apc_cache_key_data_t {
++    struct {
++        dev_t device;             /* the filesystem device */
++        ino_t inode;              /* the filesystem inode */
++    } file;
++    struct {
++        const char *identifier;
++        int identifier_len;
++    } user;
++    struct {
++        const char *fullpath;
++        int fullpath_len;
++    } fpfile;
++} apc_cache_key_data_t;
++
++typedef struct apc_cache_key_t apc_cache_key_t;
++struct apc_cache_key_t {
++    apc_cache_key_data_t data;
++    time_t mtime;                 /* the mtime of this cached entry */
++    unsigned char type;
++};
++/* }}} */
++
++/* {{{ struct definition: apc_cache_entry_t */
++typedef union _apc_cache_entry_value_t {
++    struct {
++        char *filename;             /* absolute path to source file */
++        zend_op_array* op_array;    /* op_array allocated in shared memory */
++        apc_function_t* functions;  /* array of apc_function_t's */
++        apc_class_t* classes;       /* array of apc_class_t's */
++    } file;
++    struct {
++        char *info; 
++        int info_len; 
++        zval *val;
++        unsigned int ttl;
++    } user;
++} apc_cache_entry_value_t;
++
++typedef struct apc_cache_entry_t apc_cache_entry_t;
++struct apc_cache_entry_t {
++    apc_cache_entry_value_t data;
++    unsigned char type;
++    unsigned char autofiltered;
++    unsigned char local;
++    int ref_count;
++    size_t mem_size;
++};
++/* }}} */
++
++/*
++ * apc_cache_create creates the shared memory compiler cache. This function
++ * should be called just once (ideally in the web server parent process, e.g.
++ * in apache), otherwise you will end up with multiple caches (which won't
++ * necessarily break anything). Returns a pointer to the cache object.
++ *
++ * size_hint is a "hint" at the total number of source files that will be
++ * cached. It determines the physical size of the hash table. Passing 0 for
++ * this argument will use a reasonable default value.
++ *
++ * gc_ttl is the maximum time a cache entry may speed on the garbage
++ * collection list. This is basically a work around for the inherent
++ * unreliability of our reference counting mechanism (see apc_cache_release).
++ *
++ * ttl is the maximum time a cache entry can idle in a slot in case the slot
++ * is needed.  This helps in cleaning up the cache and ensuring that entries 
++ * hit frequently stay cached and ones not hit very often eventually disappear.
++ */
++extern T apc_cache_create(int size_hint, int gc_ttl, int ttl);
++
++/*
++ * apc_cache_destroy releases any OS resources associated with a cache object.
++ * Under apache, this function can be safely called by the child processes
++ * when they exit.
++ */
++extern void apc_cache_destroy(T cache);
++
++/*
++ * apc_cache_clear empties a cache. This can safely be called at any time,
++ * even while other server processes are executing cached source files.
++ */
++extern void apc_cache_clear(T cache);
++
++/*
++ * apc_cache_insert adds an entry to the cache, using a filename as a key.
++ * Internally, the filename is translated to a canonical representation, so
++ * that relative and absolute filenames will map to a single key. Returns
++ * non-zero if the file was successfully inserted, 0 otherwise. If 0 is
++ * returned, the caller must free the cache entry by calling
++ * apc_cache_free_entry (see below).
++ *
++ * key is the value created by apc_cache_make_file_key for file keys.
++ *
++ * value is a cache entry returned by apc_cache_make_entry (see below).
++ */
++extern int apc_cache_insert(T cache, apc_cache_key_t key,
++                            apc_cache_entry_t* value, time_t t);
++
++extern int apc_cache_user_insert(T cache, apc_cache_key_t key,
++                            apc_cache_entry_t* value, time_t t, int exclusive TSRMLS_DC);
++
++/*
++ * apc_cache_find searches for a cache entry by filename, and returns a
++ * pointer to the entry if found, NULL otherwise.
++ *
++ * key is a value created by apc_cache_make_file_key for file keys.
++ */
++extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t);
++
++/*
++ * apc_cache_user_find searches for a cache entry by its hashed identifier, 
++ * and returns a pointer to the entry if found, NULL otherwise.
++ *
++ */
++extern apc_cache_entry_t* apc_cache_user_find(T cache, char* strkey, int keylen, time_t t);
++
++/*
++ * apc_cache_user_delete finds an entry in the user cache and deletes it.
++ */
++extern int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen);
++
++/* apc_cach_fetch_zval takes a zval in the cache and reconstructs a runtime
++ * zval from it.
++ *
++ */
++zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate);
++
++/*
++ * apc_cache_release decrements the reference count associated with a cache
++ * entry. Calling apc_cache_find automatically increments the reference count,
++ * and this function must be called post-execution to return the count to its
++ * original value. Failing to do so will prevent the entry from being
++ * garbage-collected.
++ *
++ * entry is the cache entry whose ref count you want to decrement.
++ */
++extern void apc_cache_release(T cache, apc_cache_entry_t* entry);
++
++/*
++ * apc_cache_make_file_key creates a key object given a relative or absolute
++ * filename and an optional list of auxillary paths to search. include_path is
++ * searched if the filename cannot be found relative to the current working
++ * directory.
++ *
++ * key points to caller-allocated storage (must not be null).
++ *
++ * filename is the path to the source file.
++ *
++ * include_path is a colon-separated list of directories to search.
++ *
++ * and finally we pass in the current request time so we can avoid
++ * caching files with a current mtime which tends to indicate that
++ * they are still being written to.
++ */
++extern int apc_cache_make_file_key(apc_cache_key_t* key,
++                                   const char* filename,
++                                   const char* include_path,
++                                   time_t t
++                                                             TSRMLS_DC);
++
++/*
++ * apc_cache_make_file_entry creates an apc_cache_entry_t object given a filename
++ * and the compilation results returned by the PHP compiler.
++ */
++extern apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
++                                                    zend_op_array* op_array,
++                                                    apc_function_t* functions,
++                                                    apc_class_t* classes);
++/*
++ * apc_cache_make_user_entry creates an apc_cache_entry_t object given an info string
++ * and the zval to be stored.
++ */
++extern apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval *val, const unsigned int ttl);
++
++extern int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t);
++
++/*
++ * Frees all memory associated with an object returned by apc_cache_make_entry
++ * (see above).
++ */
++extern void apc_cache_free_entry(apc_cache_entry_t* entry);
++
++/* {{{ struct definition: apc_cache_link_data_t */
++typedef union _apc_cache_link_data_t {
++    struct {
++        char *filename;
++        dev_t device;
++        ino_t inode;
++    } file;
++    struct {
++        char *info;
++        unsigned int ttl;
++    } user;
++} apc_cache_link_data_t;
++/* }}} */
++
++/* {{{ struct definition: apc_cache_link_t */
++typedef struct apc_cache_link_t apc_cache_link_t;
++struct apc_cache_link_t {
++    apc_cache_link_data_t data;
++    unsigned char type;
++    int num_hits;
++    time_t mtime;
++    time_t creation_time;
++    time_t deletion_time;
++    time_t access_time;
++    int ref_count;
++    size_t mem_size;
++    apc_cache_link_t* next;
++};
++/* }}} */
++
++/* {{{ struct definition: apc_cache_info_t */
++typedef struct apc_cache_info_t apc_cache_info_t;
++struct apc_cache_info_t {
++    int num_slots;
++    int num_hits;
++    int num_misses;
++    int ttl;
++    apc_cache_link_t* list;
++    apc_cache_link_t* deleted_list;
++    time_t start_time;
++    int expunges;
++    int num_entries;
++    int num_inserts;
++    size_t mem_size;
++};
++/* }}} */
++
++extern apc_cache_info_t* apc_cache_info(T cache, zend_bool limited);
++extern void apc_cache_free_info(apc_cache_info_t* info);
++extern void apc_cache_expunge(apc_cache_t* cache, time_t t);
++extern void apc_cache_unlock(apc_cache_t* cache);
++extern zend_bool apc_cache_busy(apc_cache_t* cache);
++extern zend_bool apc_cache_write_lock(apc_cache_t* cache);
++extern void apc_cache_write_unlock(apc_cache_t* cache);
++
++/* 
++ * Process local cache, which keeps a refcount hungry version of the slots
++ * for quick access without a lock - as long as the entry exists in local
++ * cache, the refcount of the shm version will be +1 more than required.
++ * It holds no data, only a shallow copy of apc_cache_entry.
++ */
++typedef struct apc_local_cache_t apc_local_cache_t; /* process-local cache */ 
++
++extern apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl);
++extern apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t);
++extern void apc_local_cache_destroy(apc_local_cache_t* cache);
++extern void apc_local_cache_cleanup(apc_local_cache_t* cache);
++
++#undef T
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_compile.c php-5.1.6/ext/APC/apc_compile.c
+--- php-5.1.6.old/ext/apc/apc_compile.c        1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_compile.c    2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,2530 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt.                                 |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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_compile.c,v 3.85 2007/03/28 07:35:55 gopalv Exp $ */
++
++#include "apc_compile.h"
++#include "apc_globals.h"
++#include "apc_zend.h"
++
++typedef void* (*ht_copy_fun_t)(void*, void*, apc_malloc_t, apc_free_t);
++typedef void  (*ht_free_fun_t)(void*, apc_free_t);
++typedef int (*ht_check_copy_fun_t)(Bucket*, va_list);
++
++#ifdef ZEND_ENGINE_2
++typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*);
++#endif
++
++#define CHECK(p) { if ((p) == NULL) return NULL; }
++
++/* {{{ internal function declarations */
++
++static int is_derived_class(zend_op_array* op_array, const char* key, int key_size);
++
++static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_malloc_t);
++
++/*
++ * The "copy" functions perform deep-copies on a particular data structure
++ * (passed as the second argument). They also optionally allocate space for
++ * the destination data structure if the first argument is null.
++ */
++static zval** my_copy_zval_ptr(zval**, const zval**, apc_malloc_t, apc_free_t);
++static zval* my_copy_zval(zval*, const zval*, apc_malloc_t, apc_free_t);
++static znode* my_copy_znode(znode*, znode*, apc_malloc_t, apc_free_t);
++static zend_op* my_copy_zend_op(zend_op*, zend_op*, apc_malloc_t, apc_free_t);
++static zend_function* my_copy_function(zend_function*, zend_function*, apc_malloc_t, apc_free_t);
++static zend_function_entry* my_copy_function_entry(zend_function_entry*, zend_function_entry*, apc_malloc_t, apc_free_t);
++static zend_class_entry* my_copy_class_entry(zend_class_entry*, zend_class_entry*, apc_malloc_t, apc_free_t);
++static HashTable* my_copy_hashtable_ex(HashTable*, HashTable*, ht_copy_fun_t, ht_free_fun_t, int, apc_malloc_t, apc_free_t, ht_check_copy_fun_t, ...);
++#define my_copy_hashtable( dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate) \
++    my_copy_hashtable_ex(dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate, NULL)
++static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate);
++#ifdef ZEND_ENGINE_2
++static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate);
++static zend_arg_info* my_copy_arg_info_array(zend_arg_info*, zend_arg_info*, uint, apc_malloc_t, apc_free_t);
++static zend_arg_info* my_copy_arg_info(zend_arg_info*, zend_arg_info*, apc_malloc_t, apc_free_t);
++#endif
++/*
++ * The "destroy" functions free the memory associated with a particular data
++ * structure but do not free the pointer to the data structure.
++ *
++ * my_destroy_zval() returns SUCCESS or FAILURE, FAILURE means that
++ * the zval* has other references elsewhere 
++ */
++static int  my_destroy_zval(zval*, apc_free_t); 
++static void my_destroy_zval_ptr(zval**, apc_free_t);
++static void my_destroy_zend_op(zend_op*, apc_free_t);
++static void my_destroy_znode(znode*, apc_free_t);
++static void my_destroy_function(zend_function*, apc_free_t);
++static void my_destroy_function_entry(zend_function_entry*, apc_free_t);
++static void my_destroy_class_entry(zend_class_entry*, apc_free_t);
++static void my_destroy_hashtable(HashTable*, ht_free_fun_t, apc_free_t);
++static void my_destroy_op_array(zend_op_array*, apc_free_t);
++#ifdef ZEND_ENGINE_2
++static void my_destroy_property_info(zend_property_info*, apc_free_t);
++static void my_destroy_arg_info_array(zend_arg_info* src, uint, apc_free_t);
++static void my_destroy_arg_info(zend_arg_info*, apc_free_t);
++#endif
++
++/*
++ * The "free" functions work exactly like their "destroy" counterparts (see
++ * above) but also free the pointer to the data structure.
++ */
++static void my_free_zval_ptr(zval**, apc_free_t);
++static void my_free_function(zend_function*, apc_free_t);
++static void my_free_hashtable(HashTable*, ht_free_fun_t, apc_free_t);
++#ifdef ZEND_ENGINE_2
++static void my_free_property_info(zend_property_info* src, apc_free_t);
++static void my_free_arg_info_array(zend_arg_info*, uint, apc_free_t);
++static void my_free_arg_info(zend_arg_info*, apc_free_t);
++#endif
++
++/*
++ * The "fixup" functions need for ZEND_ENGINE_2
++ */
++#ifdef ZEND_ENGINE_2
++static void my_fixup_function( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
++static void my_fixup_hashtable( HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst );
++/* my_fixup_function_for_execution is the same as my_fixup_function
++ * but named differently for clarity
++ */
++#define my_fixup_function_for_execution my_fixup_function
++
++#ifdef ZEND_ENGINE_2_2
++static void my_fixup_property_info( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
++#define my_fixup_property_info_for_execution my_fixup_property_info
++#endif
++
++#endif
++
++/*
++ * These functions return "1" if the member/function is
++ * defined/overridden in the 'current' class and not inherited.
++ */
++static int my_check_copy_function(Bucket* src, va_list args);
++static int my_check_copy_default_property(Bucket* p, va_list args);
++#ifdef ZEND_ENGINE_2
++static int my_check_copy_property_info(Bucket* src, va_list args);
++static int my_check_copy_static_member(Bucket* src, va_list args);
++#endif
++
++/* }}} */
++
++/* {{{ check_op_array_integrity */
++#if 0
++static void check_op_array_integrity(zend_op_array* src)
++{
++    int i, j;
++
++    /* These sorts of checks really aren't particularly effective, but they
++     * can provide a welcome sanity check when debugging. Just don't enable
++     * for production use!  */
++
++    assert(src->refcount != NULL);
++    assert(src->opcodes != NULL);
++    assert(src->last > 0);
++
++    for (i = 0; i < src->last; i++) {
++        zend_op* op = &src->opcodes[i];
++        znode* nodes[] = { &op->result, &op->op1, &op->op2 };
++        for (j = 0; j < 3; j++) {
++            assert(nodes[j]->op_type == IS_CONST ||
++                   nodes[j]->op_type == IS_VAR ||
++                   nodes[j]->op_type == IS_TMP_VAR ||
++                   nodes[j]->op_type == IS_UNUSED);
++
++            if (nodes[j]->op_type == IS_CONST) {
++                int type = nodes[j]->u.constant.type;
++                assert(type == IS_RESOURCE ||
++                       type == IS_BOOL ||
++                       type == IS_LONG ||
++                       type == IS_DOUBLE ||
++                       type == IS_NULL ||
++                       type == IS_CONSTANT ||
++                       type == IS_STRING ||
++                       type == FLAG_IS_BC ||
++                       type == IS_ARRAY ||
++                       type == IS_CONSTANT_ARRAY ||
++                       type == IS_OBJECT);
++            }
++        }
++    }
++}
++#endif
++/* }}} */
++
++/* {{{ is_derived_class */
++static int is_derived_class(zend_op_array* op_array, const char* key, int key_size)
++{
++    int i;
++
++    /*
++     * Scan the op_array for execution-time class declarations of derived
++     * classes. If we find one whose key matches our current class key, we
++     * know the current class is a derived class.
++     *
++     * This check is exceedingly inefficient (fortunately it only has to occur
++     * once, when the source file is first compiled and cached), but the
++     * compiler should save this information for us -- definitely a candidate
++     * for a Zend Engine patch.
++     *
++     * XXX checking for derived classes provides a minimal (albeit measurable)
++     * speed up. It may not be worth the added complexity -- considere
++     * removing this optimization.
++     */
++
++    for (i = 0; i < op_array->last; i++) {
++        zend_op* op = &op_array->opcodes[i];
++
++#ifdef ZEND_ENGINE_2        
++        if (op->opcode == ZEND_DECLARE_CLASS &&
++            op->extended_value == ZEND_DECLARE_INHERITED_CLASS)
++#else            
++        if (op->opcode == ZEND_DECLARE_FUNCTION_OR_CLASS &&
++            op->extended_value == ZEND_DECLARE_INHERITED_CLASS)
++#endif            
++        {
++            if (op->op1.u.constant.value.str.len == key_size &&
++                !memcmp(op->op1.u.constant.value.str.val, key, key_size))
++            {
++                return 1;
++            }
++        }
++    }
++
++    return 0;
++}
++/* }}} */
++
++/* {{{ my_bitwise_copy_function */
++static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate)
++{
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zend_function*) allocate(sizeof(src[0])));
++    }
++
++    /* We only need to do a bitwise copy */
++    memcpy(dst, src, sizeof(src[0]));
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_zval_ptr */
++static zval** my_copy_zval_ptr(zval** dst, const zval** src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    zval* dst_new;
++    
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zval**) allocate(sizeof(zval*)));
++        local_dst_alloc = 1;
++    }
++
++    if(!(dst[0] = (zval*) allocate(sizeof(zval)))) {
++        if(local_dst_alloc) deallocate(dst);
++        return NULL;
++    }
++    dst_new = my_copy_zval(*dst, *src, allocate, deallocate);
++    if(dst_new != *dst) {
++        deallocate(*dst);
++        *dst = dst_new;
++    }
++
++    (*dst)->refcount = (*src)->refcount;
++    (*dst)->is_ref = (*src)->is_ref;
++    
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_zval */
++static zval* my_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    zval **tmp;
++    TSRMLS_FETCH();
++    
++    assert(dst != NULL);
++    assert(src != NULL);
++
++    memcpy(dst, src, sizeof(src[0]));
++
++    switch (src->type & ~IS_CONSTANT_INDEX) {
++    case IS_RESOURCE:
++    case IS_BOOL:
++    case IS_LONG:
++    case IS_DOUBLE:
++    case IS_NULL:
++        break;
++
++    case IS_CONSTANT:
++    case IS_STRING:
++#ifndef ZEND_ENGINE_2        
++    case FLAG_IS_BC:
++#endif        
++        if (src->value.str.val) {
++            CHECK(dst->value.str.val = apc_xmemcpy(src->value.str.val,
++                                                   src->value.str.len+1,
++                                                   allocate));
++        }
++        break;
++    
++    case IS_ARRAY:
++
++        if(APCG(copied_zvals)) {
++            if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
++                (*tmp)->refcount++;
++                return *tmp;
++            }
++        
++            zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&dst, sizeof(zval*), NULL);
++        }
++        /* fall through */
++ 
++    case IS_CONSTANT_ARRAY:
++
++        CHECK(dst->value.ht =
++            my_copy_hashtable(NULL,
++                              src->value.ht,
++                              (ht_copy_fun_t) my_copy_zval_ptr,
++                              (ht_free_fun_t) my_free_zval_ptr,
++                              1,
++                              allocate, deallocate));
++        break;
++
++    case IS_OBJECT:
++#ifndef ZEND_ENGINE_2        
++        CHECK(dst->value.obj.ce =
++            my_copy_class_entry(NULL, src->value.obj.ce, allocate, deallocate));
++
++        if(!(dst->value.obj.properties = my_copy_hashtable(NULL,
++                              src->value.obj.properties,
++                              (ht_copy_fun_t) my_copy_zval_ptr,
++                              (ht_free_fun_t) my_free_zval_ptr,
++                              1,
++                              allocate, deallocate))) {
++            my_destroy_class_entry(dst->value.obj.ce, deallocate);
++            return NULL;
++        }
++        break;
++#else
++      dst->type = IS_NULL;
++#endif        
++        break;
++
++    default:
++        assert(0);
++    }
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_znode */
++static znode* my_copy_znode(znode* dst, znode* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    assert(dst != NULL);
++    assert(src != NULL);
++
++    memcpy(dst, src, sizeof(src[0]));
++
++#ifdef IS_CV
++    assert(dst ->op_type == IS_CONST ||
++           dst ->op_type == IS_VAR ||
++           dst ->op_type == IS_CV ||
++           dst ->op_type == IS_TMP_VAR ||
++           dst ->op_type == IS_UNUSED);
++#else
++    assert(dst ->op_type == IS_CONST ||
++           dst ->op_type == IS_VAR ||
++           dst ->op_type == IS_TMP_VAR ||
++           dst ->op_type == IS_UNUSED);
++#endif
++
++    if (src->op_type == IS_CONST) {
++        if(!my_copy_zval(&dst->u.constant, &src->u.constant, allocate, deallocate)) {
++            return NULL;
++        }
++    }
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_zend_op */
++static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    assert(dst != NULL);
++    assert(src != NULL);
++
++    memcpy(dst, src, sizeof(src[0]));
++
++    if( my_copy_znode(&dst->result, &src->result, allocate, deallocate) == NULL 
++            || my_copy_znode(&dst->op1, &src->op1, allocate, deallocate) == NULL
++            || my_copy_znode(&dst->op2, &src->op2, allocate, deallocate) == NULL)
++    {
++        return NULL;
++    }
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_function */
++static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++      TSRMLS_FETCH();
++
++    assert(src != NULL);
++
++    if(!dst) local_dst_alloc = 1;
++    CHECK(dst = my_bitwise_copy_function(dst, src, allocate));
++
++    switch (src->type) {
++    case ZEND_INTERNAL_FUNCTION:
++    case ZEND_OVERLOADED_FUNCTION:
++        /* shallow copy because op_array is internal */
++        dst->op_array = src->op_array;
++        break;
++        
++    case ZEND_USER_FUNCTION:
++    case ZEND_EVAL_CODE:
++        if(!apc_copy_op_array(&dst->op_array,
++                                &src->op_array,
++                                allocate, deallocate TSRMLS_CC)) {
++            if(local_dst_alloc) deallocate(dst);
++            return NULL;
++        }
++        break;
++
++    default:
++        assert(0);
++    }
++#ifdef ZEND_ENGINE_2
++    /* 
++     * op_array bitwise copying overwrites what ever you modified
++     * before apc_copy_op_array - which is why this code is outside 
++     * my_bitwise_copy_function. 
++     */
++
++    /* zend_do_inheritance will re-look this up, because the pointers
++     * in prototype are from a function table of another class. It just
++     * helps if that one is from EG(class_table).
++     */
++    dst->common.prototype = NULL; 
++
++    /* once a method is marked as ZEND_ACC_IMPLEMENTED_ABSTRACT then you
++     * have to carry around a prototype. Thankfully zend_do_inheritance
++     * sets this properly as well
++     */
++    dst->common.fn_flags = src->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
++#endif
++
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_function_entry */
++static zend_function_entry* my_copy_function_entry(zend_function_entry* dst, zend_function_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zend_function_entry*) allocate(sizeof(src[0])));
++        local_dst_alloc = 1;
++    }
++
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(src[0]));
++
++    dst->fname = NULL;
++#ifdef ZEND_ENGINE_2
++    dst->arg_info = NULL;
++#else
++    dst->func_arg_types = NULL;
++#endif
++
++    if (src->fname) {
++        if(!(dst->fname = apc_xstrdup(src->fname, allocate))) {
++            goto cleanup;
++        }
++    }
++
++#ifdef ZEND_ENGINE_2    
++    if (src->arg_info) {
++        if(!(dst->arg_info = my_copy_arg_info_array(NULL,
++                                                src->arg_info,
++                                                src->num_args,
++                                                allocate,
++                                                deallocate))) {
++            goto cleanup;
++        }
++    }
++#else    
++    if (src->func_arg_types) {
++        if(!(dst->func_arg_types = apc_xmemcpy(src->func_arg_types,
++                                                src->func_arg_types[0]+1,
++                                                allocate))) {
++            goto cleanup;
++        }
++    }
++#endif
++
++    return dst;
++
++cleanup:
++    if(dst->fname) deallocate(dst->fname);
++    if(local_dst_alloc) deallocate(dst);
++    return NULL;
++}
++/* }}} */
++
++#ifdef ZEND_ENGINE_2
++/* {{{ my_copy_property_info */
++static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
++        local_dst_alloc = 1;
++    }
++
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src));
++
++    dst->name = NULL;
++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
++    dst->doc_comment = NULL;
++#endif
++
++    if (src->name) {
++        /* private members are stored inside property_info as a mangled
++         * string of the form:
++         *      \0<classname>\0<membername>\0
++         */
++        if(!(dst->name = 
++                    apc_xmemcpy(src->name, src->name_length+1, allocate))) {
++            goto cleanup;
++        }
++    }
++
++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
++    if (src->doc_comment) {
++        if( !(dst->doc_comment =
++                    apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
++            goto cleanup;
++        }
++    }
++#endif
++
++    return dst;
++
++cleanup:
++    if(dst->name) deallocate(dst->name);
++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
++    if(dst->doc_comment) deallocate(dst->doc_comment);
++#endif
++    if(local_dst_alloc) deallocate(dst);
++    return NULL;
++}
++/* }}} */
++
++/* {{{ my_copy_property_info_for_execution */
++static zend_property_info* my_copy_property_info_for_execution(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
++        local_dst_alloc = 1;
++    }
++
++    /* We need only a shallow copy */
++    memcpy(dst, src, sizeof(*src));
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_arg_info_array */
++static zend_arg_info* my_copy_arg_info_array(zend_arg_info* dst, zend_arg_info* src, uint num_args, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    int i = 0;
++
++    
++    if (!dst) {
++        CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)*num_args));
++        local_dst_alloc = 1;
++    }
++
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src)*num_args);
++
++    for(i=0; i < num_args; i++) {
++        if(!(my_copy_arg_info( &dst[i], &src[i], allocate, deallocate))) {            
++            if(i) my_destroy_arg_info_array(dst, i-1, deallocate);
++            if(local_dst_alloc) deallocate(dst);
++            return NULL;
++        }
++    }
++
++    return dst;    
++}
++/* }}} */
++
++/* {{{ my_copy_arg_info */
++static zend_arg_info* my_copy_arg_info(zend_arg_info* dst, zend_arg_info* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)));
++        local_dst_alloc = 1;
++    }
++
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src));
++
++    dst->name = NULL;
++    dst->class_name = NULL;
++
++    if (src->name) {
++        if(!(dst->name = 
++                    apc_xmemcpy(src->name, src->name_len+1, allocate))) {
++            goto cleanup;
++        }
++    }
++
++    if (src->class_name) {
++        if(!(dst->class_name = 
++                    apc_xmemcpy(src->class_name, src->class_name_len+1, allocate))) {
++            goto cleanup;
++        }
++    }
++
++    return dst;
++
++cleanup:
++    if(dst->name) deallocate(dst->name);
++    if(dst->class_name) deallocate(dst->name);
++    if(local_dst_alloc) deallocate(dst);
++    return NULL;
++}
++/* }}} */
++#endif
++
++/* {{{ my_copy_class_entry */
++static zend_class_entry* my_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    int i = 0;
++
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zend_class_entry*) allocate(sizeof(*src)));
++        local_dst_alloc = 1;
++    }
++
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src));
++
++    dst->name = NULL;
++    dst->builtin_functions = NULL;
++    memset(&dst->function_table, 0, sizeof(dst->function_table));
++    memset(&dst->default_properties, 0, sizeof(dst->default_properties));
++#ifndef ZEND_ENGINE_2
++    dst->refcount = NULL;
++#else
++    dst->static_members = NULL;
++    dst->doc_comment = NULL;
++    dst->filename = NULL;
++    memset(&dst->properties_info, 0, sizeof(dst->properties_info));
++    memset(&dst->constants_table, 0, sizeof(dst->constants_table));
++    memset(&dst->default_static_members, 0, sizeof(dst->default_static_members));
++#endif
++
++    if (src->name) {
++        if(!(dst->name = apc_xstrdup(src->name, allocate))) {
++            goto cleanup;
++        }
++    }
++
++#ifndef ZEND_ENGINE_2    
++    if(!(dst->refcount = apc_xmemcpy(src->refcount,
++                                      sizeof(src->refcount[0]),
++                                      allocate))) {
++        goto cleanup;
++    }
++#endif        
++
++    if(!(my_copy_hashtable_ex(&dst->function_table,
++                            &src->function_table,
++                            (ht_copy_fun_t) my_copy_function,
++                            (ht_free_fun_t) my_free_function,
++                            0,
++                            allocate, deallocate,
++                            (ht_check_copy_fun_t) my_check_copy_function,
++                            src))) {
++        goto cleanup;
++    }
++
++#ifdef ZEND_ENGINE_2
++
++    /* the interfaces are populated at runtime using ADD_INTERFACE */
++    dst->interfaces = NULL; 
++
++    /* the current count includes inherited interfaces as well,
++       the real dynamic ones are the first <n> which are zero'd
++       out in zend_do_end_class_declaration */
++    for(i = 0 ; i < src->num_interfaces ; i++) {
++        if(src->interfaces[i])
++        {
++            dst->num_interfaces = i;
++            break;
++        }
++    }
++
++    /* these will either be set inside my_fixup_hashtable or 
++     * they will be copied out from parent inside zend_do_inheritance 
++     */
++    dst->constructor =  NULL;
++    dst->destructor = NULL;
++    dst->clone = NULL;
++    dst->__get = NULL;
++    dst->__set = NULL;
++    dst->__unset = NULL;
++    dst->__isset = NULL;
++    dst->__call = NULL;
++#ifdef ZEND_ENGINE_2_2
++    dst->__tostring = NULL;
++#endif
++
++    /* unset function proxies */
++    dst->serialize_func = NULL;
++    dst->unserialize_func = NULL;
++    
++    my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function, src, dst);
++#endif
++
++    if(!(my_copy_hashtable_ex(&dst->default_properties,
++                            &src->default_properties,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            (ht_free_fun_t) my_free_zval_ptr,
++                            1,
++                            allocate,deallocate,
++                            (ht_check_copy_fun_t) my_check_copy_default_property,
++                            src))) {
++        goto cleanup;
++    }
++
++#ifdef ZEND_ENGINE_2
++    
++    if(!(my_copy_hashtable_ex(&dst->properties_info,
++                            &src->properties_info,
++                            (ht_copy_fun_t) my_copy_property_info,
++                            (ht_free_fun_t) my_free_property_info,
++                            0,
++                            allocate, deallocate,
++                            (ht_check_copy_fun_t) my_check_copy_property_info,
++                            src))) {
++        goto cleanup;
++    }
++
++#ifdef ZEND_ENGINE_2_2
++    /* php5.2 introduced a scope attribute for property info */
++    my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
++#endif
++    
++    if(!my_copy_hashtable_ex(&dst->default_static_members,
++                            &src->default_static_members,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            (ht_free_fun_t) my_free_zval_ptr,
++                            1,
++                            allocate, deallocate,
++                            (ht_check_copy_fun_t) my_check_copy_static_member,
++                            src,
++                            &src->default_static_members)) {
++        goto cleanup;
++    }
++    if(src->static_members != &src->default_static_members)
++    {
++        if(!(dst->static_members = my_copy_hashtable_ex(NULL,
++                            src->static_members,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            (ht_free_fun_t) my_free_zval_ptr,
++                            1,
++                            allocate, deallocate,
++                            (ht_check_copy_fun_t) my_check_copy_static_member,
++                            src,
++                            src->static_members))) {
++            goto cleanup;
++        }
++    }
++    else
++    {
++        dst->static_members = &dst->default_static_members;
++    }
++
++    if(!(my_copy_hashtable(&dst->constants_table,
++                            &src->constants_table,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            (ht_free_fun_t) my_free_zval_ptr,
++                            1,
++                            allocate, deallocate))) {
++        goto cleanup;
++    }
++
++    if (src->doc_comment) {
++        if(!(dst->doc_comment =
++                    apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
++            goto cleanup;
++        }
++    }
++#endif
++    
++    if (src->builtin_functions) {
++        int i, n;
++
++        for (n = 0; src->type == ZEND_INTERNAL_CLASS && src->builtin_functions[n].fname != NULL; n++) {}
++
++        if(!(dst->builtin_functions =
++            (zend_function_entry*)
++                allocate((n + 1) * sizeof(zend_function_entry)))) {
++            goto cleanup;
++        }
++
++
++        for (i = 0; i < n; i++) {
++            if(!my_copy_function_entry(&dst->builtin_functions[i],
++                                   &src->builtin_functions[i],
++                                   allocate, deallocate)) {
++                int ii;
++
++                for(ii=i-1; i>=0; i--) my_destroy_function_entry(&dst->builtin_functions[ii], deallocate);
++                goto cleanup;
++            }
++        }
++        dst->builtin_functions[n].fname = NULL;
++    }
++
++#ifdef ZEND_ENGINE_2
++    if (src->filename) {
++        if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
++            goto cleanup;
++        }
++    }
++#endif
++   
++    return dst;
++
++
++cleanup:
++    if(dst->name) deallocate(dst->name);
++#ifdef ZEND_ENGINE_2
++    if(dst->doc_comment) deallocate(dst->doc_comment);
++    if(dst->filename) deallocate(dst->filename);
++#else
++    if(dst->refcount) deallocate(dst->refcount);
++#endif
++    
++    if(dst->builtin_functions) deallocate(dst->builtin_functions);
++    if(dst->function_table.arBuckets) my_destroy_hashtable(&dst->function_table, (ht_free_fun_t) my_free_function, deallocate);
++    if(dst->default_properties.arBuckets) my_destroy_hashtable(&dst->default_properties, (ht_free_fun_t) my_free_zval_ptr, deallocate);
++
++#ifdef ZEND_ENGINE_2
++    if(dst->properties_info.arBuckets) my_destroy_hashtable(&dst->properties_info, (ht_free_fun_t) my_free_property_info, deallocate);
++    if(dst->default_static_members.arBuckets)
++    {
++        my_destroy_hashtable(&dst->default_static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
++    }
++    if(dst->static_members && dst->static_members != &(dst->default_static_members))
++    {
++        my_destroy_hashtable(dst->static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
++        deallocate(dst->static_members);
++    }
++    if(dst->constants_table.arBuckets) my_destroy_hashtable(&dst->constants_table, (ht_free_fun_t) my_free_zval_ptr, deallocate);
++#endif
++    if(local_dst_alloc) deallocate(dst);
++
++    return NULL;
++}
++/* }}} */
++
++/* {{{ my_copy_hashtable */
++static HashTable* my_copy_hashtable_ex(HashTable* dst,
++                                    HashTable* src,
++                                    ht_copy_fun_t copy_fn,
++                                    ht_free_fun_t free_fn,
++                                    int holds_ptrs,
++                                    apc_malloc_t allocate, 
++                                    apc_free_t deallocate,
++                                    ht_check_copy_fun_t check_fn,
++                                    ...)
++{
++    Bucket* curr = NULL;
++    Bucket* prev = NULL;
++    Bucket* newp = NULL;
++    int first = 1;
++    int local_dst_alloc = 0;
++    int index = 0;
++
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (HashTable*) allocate(sizeof(src[0])));
++        local_dst_alloc = 1;
++    }
++
++    memcpy(dst, src, sizeof(src[0]));
++
++    /* allocate buckets for the new hashtable */
++    if(!(dst->arBuckets = allocate(dst->nTableSize * sizeof(Bucket*)))) {
++        if(local_dst_alloc) deallocate(dst);
++        return NULL;
++    }
++
++    memset(dst->arBuckets, 0, dst->nTableSize * sizeof(Bucket*));
++    dst->pInternalPointer = NULL;
++    dst->pListHead = NULL;
++    
++    for (curr = src->pListHead; curr != NULL; curr = curr->pListNext) {
++        int n = curr->h % dst->nTableSize;
++
++        if(check_fn) {
++            va_list args;
++            va_start(args, check_fn);
++
++            /* Call the check_fn to see if the current bucket 
++             * needs to be copied out
++             */
++            if(!check_fn(curr, args)) {
++                dst->nNumOfElements--;
++                continue;
++            }
++
++            va_end(args);
++        }
++
++        /* create a copy of the bucket 'curr' */
++        if(!(newp =
++            (Bucket*) apc_xmemcpy(curr,
++                                  sizeof(Bucket) + curr->nKeyLength - 1,
++                                  allocate))) {
++            goto cleanup;
++        }
++
++        /* insert 'newp' into the linked list at its hashed index */
++        if (dst->arBuckets[n]) {
++            newp->pNext = dst->arBuckets[n];
++            newp->pLast = NULL;
++            newp->pNext->pLast = newp;
++        }
++        else {
++            newp->pNext = newp->pLast = NULL;
++        }
++
++        dst->arBuckets[n] = newp;
++
++        /* copy the bucket data using our 'copy_fn' callback function */
++        if(!(newp->pData = copy_fn(NULL, curr->pData, allocate, deallocate))) {
++            goto cleanup;
++        }
++
++        if (holds_ptrs) {
++            memcpy(&newp->pDataPtr, newp->pData, sizeof(void*));
++        }
++        else {
++            newp->pDataPtr = NULL;
++        }
++
++        /* insert 'newp' into the table-thread linked list */
++        newp->pListLast = prev;
++        newp->pListNext = NULL;
++
++        if (prev) {
++            prev->pListNext = newp;
++        }
++
++        if (first) {
++            dst->pListHead = newp;
++            first = 0;
++        }
++
++        prev = newp;
++    }
++
++    dst->pListTail = newp;
++
++    return dst;
++    
++    cleanup:
++    for(index = 0; index < dst->nTableSize; index++)
++    {
++        curr = dst->arBuckets[index];
++        while(curr != NULL)
++        {
++            Bucket * tmp = curr;
++            if(curr->pData && free_fn)
++            {
++                free_fn(curr->pData, deallocate);
++            }
++            curr = curr->pNext;
++            deallocate(tmp);
++        }
++    }   
++    deallocate(dst->arBuckets);
++    if(local_dst_alloc) deallocate(dst);
++    else dst->arBuckets = NULL;
++
++    return NULL;
++}
++/* }}} */
++
++/* {{{ my_copy_static_variables */
++static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate)
++{ 
++    if (src->static_variables == NULL) {
++        return NULL;
++    }
++
++    return my_copy_hashtable(NULL,
++                             src->static_variables,
++                             (ht_copy_fun_t) my_copy_zval_ptr,
++                             (ht_free_fun_t) my_free_zval_ptr,
++                             1,
++                             allocate, deallocate);
++}
++/* }}} */
++
++/* {{{ apc_copy_zval */
++zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    int local_dst_alloc = 0;
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zval*) allocate(sizeof(zval)));
++        local_dst_alloc = 1;
++    }
++
++    dst = my_copy_zval(dst, src, allocate, deallocate);
++    if(!dst) {
++        if(local_dst_alloc) deallocate(dst);
++        return NULL;
++    }
++    return dst; 
++}
++/* }}} */
++
++#ifdef ZEND_ENGINE_2
++/* {{{ apc_fixup_op_array_jumps */
++static void apc_fixup_op_array_jumps(zend_op_array *dst, zend_op_array *src )
++{
++    int i;
++
++    for (i=0; i < dst->last; ++i) {
++        zend_op *zo = &(dst->opcodes[i]);
++        /*convert opline number to jump address*/
++        switch (zo->opcode) {
++            case ZEND_JMP:
++                /*Note: if src->opcodes != dst->opcodes then we need to the opline according to src*/
++                zo->op1.u.jmp_addr = dst->opcodes + (zo->op1.u.jmp_addr - src->opcodes);
++                break;
++            case ZEND_JMPZ:
++            case ZEND_JMPNZ:
++            case ZEND_JMPZ_EX:
++            case ZEND_JMPNZ_EX:
++                zo->op2.u.jmp_addr = dst->opcodes + (zo->op2.u.jmp_addr - src->opcodes);
++                break;
++            default:
++                break;
++        }
++    }
++}
++/* }}} */
++#endif
++
++/* {{{ apc_copy_op_array */
++zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
++{
++    int i;
++    int local_dst_alloc = 0;
++    apc_fileinfo_t fileinfo;
++    char canon_path[MAXPATHLEN];
++    char *fullpath = NULL;
++#ifdef ZEND_ENGINE_2
++    apc_opflags_t * flags = NULL;
++#endif
++
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zend_op_array*) allocate(sizeof(src[0])));
++        local_dst_alloc = 1;
++    }
++
++    if(APCG(apc_optimize_function)) {
++        APCG(apc_optimize_function)(src TSRMLS_CC);
++    }
++    
++    /* start with a bitwise copy of the array */
++    memcpy(dst, src, sizeof(src[0]));
++
++    dst->function_name = NULL;
++    dst->filename = NULL;
++    dst->refcount = NULL;
++    dst->opcodes = NULL;
++    dst->brk_cont_array = NULL;
++    dst->static_variables = NULL;
++#ifdef ZEND_ENGINE_2
++    dst->try_catch_array = NULL;
++    dst->arg_info = NULL;
++    dst->doc_comment = NULL;
++#else
++    dst->arg_types = NULL;
++#endif
++#ifdef ZEND_ENGINE_2_1
++    dst->vars = NULL;
++#endif
++
++    /* copy the arg types array (if set) */
++#ifdef ZEND_ENGINE_2
++    if (src->arg_info) {
++        if(!(dst->arg_info = my_copy_arg_info_array(NULL,
++                                                src->arg_info,
++                                                src->num_args,
++                                                allocate,
++                                                deallocate))) {
++            goto cleanup;
++        }
++    }
++#else    
++    if (src->arg_types) {
++        if(!(dst->arg_types = apc_xmemcpy(src->arg_types,
++                        sizeof(src->arg_types[0]) * (src->arg_types[0]+1),
++                        allocate))) {
++            goto cleanup;
++        }
++    }
++#endif
++
++    if (src->function_name) {
++        if(!(dst->function_name = apc_xstrdup(src->function_name, allocate))) {
++            goto cleanup;
++        }
++    }
++    if (src->filename) {
++        if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
++            goto cleanup;
++        }
++    }
++
++    if(!(dst->refcount = apc_xmemcpy(src->refcount,
++                                      sizeof(src->refcount[0]),
++                                      allocate))) {
++        goto cleanup;
++    }
++
++    /* deep-copy the opcodes */
++    if(!(dst->opcodes = (zend_op*) allocate(sizeof(zend_op) * src->last))) {
++        goto cleanup;
++    }
++
++#ifdef ZEND_ENGINE_2
++    if(APCG(reserved_offset) != -1) {
++        /* Insanity alert: the void* pointer is cast into an apc_opflags_t 
++         * struct. apc_zend_init() checks to ensure that it fits in a void* */
++        flags = (apc_opflags_t*) & (dst->reserved[APCG(reserved_offset)]);
++        memset(flags, 0, sizeof(apc_opflags_t));
++        /* assert(sizeof(apc_opflags_t) < sizeof(dst->reserved)); */
++    }
++#endif
++    
++    for (i = 0; i < src->last; i++) {
++#ifdef ZEND_ENGINE_2
++        zend_op *zo = &(src->opcodes[i]);
++        /* a lot of files are merely constant arrays with no jumps */
++        switch (zo->opcode) {
++            case ZEND_JMP:
++            case ZEND_JMPZ:
++            case ZEND_JMPNZ:
++            case ZEND_JMPZ_EX:
++            case ZEND_JMPNZ_EX:
++                if(flags != NULL) {
++                    flags->has_jumps = 1;
++                }
++                break;
++#ifdef ZEND_ENGINE_2
++            /* auto_globals_jit was not in php-4.3.* */
++            case ZEND_FETCH_R:
++            case ZEND_FETCH_W:
++            case ZEND_FETCH_IS:
++            case ZEND_FETCH_FUNC_ARG:
++                if(PG(auto_globals_jit) && flags != NULL)
++                {
++                     /* The fetch is only required if auto_globals_jit=1  */
++                    if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&
++                            zo->op1.op_type == IS_CONST && 
++                            zo->op1.u.constant.type == IS_STRING) {
++                        znode * varname = &zo->op1;
++                        if (varname->u.constant.value.str.val[0] == '_') {
++#define SET_IF_AUTOGLOBAL(member) \
++    if(!strcmp(varname->u.constant.value.str.val, #member)) \
++        flags->member = 1 /* no ';' here */
++                            SET_IF_AUTOGLOBAL(_GET);
++                            else SET_IF_AUTOGLOBAL(_POST);
++                            else SET_IF_AUTOGLOBAL(_COOKIE);
++                            else SET_IF_AUTOGLOBAL(_SERVER);
++                            else SET_IF_AUTOGLOBAL(_ENV);
++                            else SET_IF_AUTOGLOBAL(_FILES);
++                            else SET_IF_AUTOGLOBAL(_REQUEST);
++                            else if(zend_is_auto_global(
++                                            varname->u.constant.value.str.val,
++                                            varname->u.constant.value.str.len
++                                            TSRMLS_CC))
++                            {
++                                flags->unknown_global = 1;
++                            }
++                        }
++                    }
++                }
++                break;
++#endif
++            case ZEND_RECV_INIT:
++                if(zo->op2.op_type == IS_CONST &&
++                    zo->op2.u.constant.type == IS_CONSTANT_ARRAY) {
++                    if(flags != NULL) {
++                        flags->deep_copy = 1;
++                    }
++                }
++                break;
++            default:
++                if((zo->op1.op_type == IS_CONST &&
++                    zo->op1.u.constant.type == IS_CONSTANT_ARRAY) ||
++                    (zo->op2.op_type == IS_CONST &&
++                        zo->op2.u.constant.type == IS_CONSTANT_ARRAY)) {
++                    if(flags != NULL) {
++                        flags->deep_copy = 1;
++                    }
++                }
++                break;
++        }
++#endif
++        if(!(my_copy_zend_op(dst->opcodes+i, src->opcodes+i, allocate, deallocate))) {
++            int ii;
++            for(ii = i-1; ii>=0; ii--) {
++                my_destroy_zend_op(dst->opcodes+ii, deallocate);
++            }
++            goto  cleanup;
++        }
++#ifdef ZEND_ENGINE_2
++/* This code breaks apc's rule#1 - cache what you compile */
++        if(APCG(fpstat)==0) {
++            if((zo->opcode == ZEND_INCLUDE_OR_EVAL) && 
++                (zo->op1.op_type == IS_CONST && zo->op1.u.constant.type == IS_STRING)) {
++                /* constant includes */
++                if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(&zo->op1.u.constant),len)) { 
++                    if (apc_search_paths(Z_STRVAL_P(&zo->op1.u.constant), PG(include_path), &fileinfo) == 0) {
++                        if((IS_ABSOLUTE_PATH(fileinfo.fullpath, strlen(fileinfo.fullpath)) && (fullpath = fileinfo.fullpath))
++                                || (fullpath = realpath(fileinfo.fullpath, canon_path))) {
++                            /* is either an absolute path or it goes through a realpath() */
++                            zend_op *dzo = &(dst->opcodes[i]);
++                            deallocate(dzo->op1.u.constant.value.str.val);
++                            dzo->op1.u.constant.value.str.len = strlen(fullpath);
++                            dzo->op1.u.constant.value.str.val = apc_xstrdup(fullpath, allocate);
++                        }
++                    }
++                }
++            }
++        }
++#endif 
++    }
++
++#ifdef ZEND_ENGINE_2
++    if(flags == NULL || flags->has_jumps) {
++        apc_fixup_op_array_jumps(dst,src);
++    }
++#endif
++
++    /* copy the break-continue array */
++    if (src->brk_cont_array) {
++        if(!(dst->brk_cont_array =
++            apc_xmemcpy(src->brk_cont_array,
++                        sizeof(src->brk_cont_array[0]) * src->last_brk_cont,
++                        allocate))) {
++            goto cleanup_opcodes;
++        }
++    }
++
++    /* copy the table of static variables */
++    if (src->static_variables) {
++        if(!(dst->static_variables = my_copy_static_variables(src, allocate, deallocate))) {
++            goto cleanup_opcodes;
++        }
++    }
++    
++#ifdef ZEND_ENGINE_2
++    if (src->try_catch_array) {
++        if(!(dst->try_catch_array = 
++                apc_xmemcpy(src->try_catch_array,
++                        sizeof(src->try_catch_array[0]) * src->last_try_catch,
++                        allocate))) {
++            goto cleanup_opcodes;
++        }
++    }
++#endif
++
++#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */
++    if (src->vars) {
++        if(!(dst->vars = apc_xmemcpy(src->vars,
++                            sizeof(src->vars[0]) * src->last_var,
++                            allocate))) {
++            goto cleanup_opcodes;
++        }
++        
++        for(i = 0; i <  src->last_var; i++) dst->vars[i].name = NULL;
++        
++        for(i = 0; i <  src->last_var; i++) {
++            if(!(dst->vars[i].name = apc_xmemcpy(src->vars[i].name,
++                                src->vars[i].name_len + 1,
++                                allocate))) {
++                dst->last_var = i;
++                goto cleanup_opcodes;
++            }
++        }
++    }
++#endif
++
++#ifdef ZEND_ENGINE_2
++    if (src->doc_comment) {
++        if (!(dst->doc_comment 
++                = apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
++            goto cleanup_opcodes;
++        }
++    }
++#endif
++
++    return dst;
++
++cleanup_opcodes:
++    if(dst->opcodes) {
++        for(i=0; i < src->last; i++) my_destroy_zend_op(dst->opcodes+i, deallocate);
++    }
++cleanup:
++    if(dst->function_name) deallocate(dst->function_name);
++    if(dst->refcount) deallocate(dst->refcount);
++    if(dst->filename) deallocate(dst->filename);
++#ifdef ZEND_ENGINE_2
++    if(dst->arg_info) my_free_arg_info_array(dst->arg_info, dst->num_args, deallocate);
++    if(dst->try_catch_array) deallocate(dst->try_catch_array);
++    if(dst->doc_comment) deallocate(dst->doc_comment);
++#else
++    if(dst->arg_types) deallocate(dst->arg_types);
++#endif
++    if(dst->opcodes) deallocate(dst->opcodes);
++    if(dst->brk_cont_array) deallocate(dst->brk_cont_array);
++    if(dst->static_variables) my_free_hashtable(dst->static_variables, (ht_free_fun_t)my_free_zval_ptr, (apc_free_t)deallocate);
++#ifdef ZEND_ENGINE_2_1
++    if (dst->vars) {
++      for(i=0; i < dst->last_var; i++) {
++            if(dst->vars[i].name) deallocate(dst->vars[i].name);    
++        }
++        deallocate(dst->vars);
++    }
++#endif
++    if(local_dst_alloc) deallocate(dst);
++    return NULL;
++}
++/* }}} */
++
++/* {{{ apc_copy_new_functions */
++apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
++{
++    apc_function_t* array;
++    int new_count;              /* number of new functions in table */
++    int i;
++
++    new_count = zend_hash_num_elements(CG(function_table)) - old_count;
++    assert(new_count >= 0);
++
++    CHECK(array =
++        (apc_function_t*)
++            allocate(sizeof(apc_function_t) * (new_count+1)));
++
++    if (new_count == 0) {
++        array[0].function = NULL;
++        return array;
++    }
++    
++    /* Skip the first `old_count` functions in the table */
++    zend_hash_internal_pointer_reset(CG(function_table));
++    for (i = 0; i < old_count; i++) {
++        zend_hash_move_forward(CG(function_table));
++    }
++
++    /* Add the next `new_count` functions to our array */
++    for (i = 0; i < new_count; i++) {
++        char* key;
++        uint key_size;
++        zend_function* fun;
++
++        zend_hash_get_current_key_ex(CG(function_table),
++                                     &key,
++                                     &key_size,
++                                     NULL,
++                                     0,
++                                     NULL);
++
++        zend_hash_get_current_data(CG(function_table), (void**) &fun);
++
++        if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
++            int ii;
++            for(ii=i-1; ii>=0; ii--) {
++                deallocate(array[ii].name);
++                my_free_function(array[ii].function, deallocate);
++            }
++            deallocate(array);
++            return NULL;
++        }
++        array[i].name_len = (int) key_size-1;
++        if(!(array[i].function = my_copy_function(NULL, fun, allocate, deallocate))) {
++            int ii;
++            deallocate(array[i].name);
++            for(ii=i-1; ii>=0; ii--) {
++                deallocate(array[ii].name);
++                my_free_function(array[ii].function, deallocate);
++            }
++            deallocate(array);
++            return NULL;
++        }
++        zend_hash_move_forward(CG(function_table));
++    }
++
++    array[i].function = NULL;
++    return array;
++}
++/* }}} */
++
++/* {{{ apc_copy_new_classes */
++apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
++{
++    apc_class_t* array;
++    int new_count;              /* number of new classes in table */
++    int i;
++    
++    new_count = zend_hash_num_elements(CG(class_table)) - old_count;
++    assert(new_count >= 0);
++
++    CHECK(array =
++        (apc_class_t*)
++            allocate(sizeof(apc_class_t)*(new_count+1)));
++    
++    if (new_count == 0) {
++        array[0].class_entry = NULL;
++        return array;
++    }
++
++    /* Skip the first `old_count` classes in the table */
++    zend_hash_internal_pointer_reset(CG(class_table));
++    for (i = 0; i < old_count; i++) {
++        zend_hash_move_forward(CG(class_table));
++    }
++
++    /* Add the next `new_count` classes to our array */
++    for (i = 0; i < new_count; i++) {
++        char* key;
++        uint key_size;
++        zend_class_entry* elem = NULL;
++
++        array[i].class_entry = NULL;
++
++        zend_hash_get_current_key_ex(CG(class_table),
++                                     &key,
++                                     &key_size,
++                                     NULL,
++                                     0,
++                                     NULL);
++
++       zend_hash_get_current_data(CG(class_table), (void**) &elem);
++  
++        
++#ifdef ZEND_ENGINE_2
++              elem = *((zend_class_entry**)elem);
++#endif
++        
++        if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
++            int ii;
++
++            for(ii=i-1; ii>=0; ii--) {
++                deallocate(array[ii].name);
++                my_destroy_class_entry(array[ii].class_entry, deallocate);
++                deallocate(array[ii].class_entry);
++            }
++            deallocate(array);
++            return NULL;
++        }
++        array[i].name_len = (int) key_size-1;
++        if(!(array[i].class_entry = my_copy_class_entry(NULL, elem, allocate, deallocate))) {
++            int ii;
++            
++            deallocate(array[i].name);
++            for(ii=i-1; ii>=0; ii--) {
++                deallocate(array[ii].name);
++                my_destroy_class_entry(array[ii].class_entry, deallocate);
++                deallocate(array[ii].class_entry);
++            }
++            deallocate(array);
++            return NULL;
++        }
++
++        /*
++         * If the class has a pointer to its parent class, save the parent
++         * name so that we can enable compile-time inheritance when we reload
++         * the child class; otherwise, set the parent name to null and scan
++         * the op_array to determine if this class inherits from some base
++         * class at execution-time.
++         */
++
++        if (elem->parent) {
++            if(!(array[i].parent_name =
++                apc_xstrdup(elem->parent->name, allocate))) {
++                int ii;
++                 
++                for(ii=i; ii>=0; ii--) {
++                    deallocate(array[ii].name);
++                    my_destroy_class_entry(array[ii].class_entry, deallocate);
++                    deallocate(array[ii].class_entry);
++                    if(ii==i) continue;
++                    if(array[ii].parent_name) deallocate(array[ii].parent_name);
++                }
++                deallocate(array);
++                return NULL;
++            }
++            array[i].is_derived = 1;
++        }
++        else {
++            array[i].parent_name = NULL;
++            array[i].is_derived = is_derived_class(op_array, key, key_size);
++        }
++
++        zend_hash_move_forward(CG(class_table));
++    }
++
++    array[i].class_entry = NULL;
++    return array;
++}
++/* }}} */
++
++/* {{{ my_destroy_zval_ptr */
++static void my_destroy_zval_ptr(zval** src, apc_free_t deallocate)
++{
++    assert(src != NULL);
++    if(my_destroy_zval(src[0], deallocate) == SUCCESS) {
++        deallocate(src[0]);
++    }
++}
++/* }}} */
++
++/* {{{ my_destroy_zval */
++static int my_destroy_zval(zval* src, apc_free_t deallocate)
++{
++    zval **tmp;
++    TSRMLS_FETCH();
++
++    switch (src->type & ~IS_CONSTANT_INDEX) {
++    case IS_RESOURCE:
++    case IS_BOOL:
++    case IS_LONG:
++    case IS_DOUBLE:
++    case IS_NULL:
++        break;
++
++    case IS_CONSTANT:
++    case IS_STRING:
++#ifndef ZEND_ENGINE_2        
++    case FLAG_IS_BC:
++#endif        
++        deallocate(src->value.str.val);
++        break;
++    
++    case IS_ARRAY:
++    
++        /* Maintain a list of zvals we've copied to properly handle recursive structures */
++        if(APCG(copied_zvals)) {
++            if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
++                (*tmp)->refcount--;
++                return FAILURE;
++            } 
++            zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&src, sizeof(zval*), NULL);
++        }
++        /* fall through */
++
++    case IS_CONSTANT_ARRAY:
++        my_free_hashtable(src->value.ht,
++                          (ht_free_fun_t) my_free_zval_ptr,
++                          deallocate);
++        break;
++
++    case IS_OBJECT:
++#ifndef ZEND_ENGINE_2        
++        my_destroy_class_entry(src->value.obj.ce, deallocate);
++        deallocate(src->value.obj.ce);
++        my_free_hashtable(src->value.obj.properties,
++                          (ht_free_fun_t) my_free_zval_ptr,
++                          deallocate);
++#endif        
++        break;
++
++    default:
++        assert(0);
++    }
++
++    return SUCCESS;
++}
++/* }}} */
++
++/* {{{ my_destroy_znode */
++static void my_destroy_znode(znode* src, apc_free_t deallocate)
++{
++    if (src->op_type == IS_CONST) {
++        my_destroy_zval(&src->u.constant, deallocate);
++    }
++}
++/* }}} */
++
++/* {{{ my_destroy_zend_op */
++static void my_destroy_zend_op(zend_op* src, apc_free_t deallocate)
++{
++    my_destroy_znode(&src->result, deallocate);
++    my_destroy_znode(&src->op1, deallocate);
++    my_destroy_znode(&src->op2, deallocate);
++}
++/* }}} */
++
++/* {{{ my_destroy_function */
++static void my_destroy_function(zend_function* src, apc_free_t deallocate)
++{
++    assert(src != NULL);
++
++    switch (src->type) {
++    case ZEND_INTERNAL_FUNCTION:
++    case ZEND_OVERLOADED_FUNCTION:
++        break;
++        
++    case ZEND_USER_FUNCTION:
++    case ZEND_EVAL_CODE:
++        my_destroy_op_array(&src->op_array, deallocate);
++        break;
++
++    default:
++        assert(0);
++    }
++}
++/* }}} */
++
++/* {{{ my_destroy_function_entry */
++static void my_destroy_function_entry(zend_function_entry* src, apc_free_t deallocate)
++{
++    assert(src != NULL);
++
++    deallocate(src->fname);
++#ifdef ZEND_ENGINE_2    
++    if (src->arg_info) {
++            my_free_arg_info_array(src->arg_info, src->num_args, deallocate);
++    }
++#else
++    if (src->func_arg_types) {
++        deallocate(src->func_arg_types);
++    }
++#endif    
++}
++/* }}} */
++
++#ifdef ZEND_ENGINE_2    
++/* {{{ my_destroy_property_info*/
++static void my_destroy_property_info(zend_property_info* src, apc_free_t deallocate)
++{
++    assert(src != NULL);
++
++    deallocate(src->name);
++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
++    if(src->doc_comment) deallocate(src->doc_comment);
++#endif
++}
++/* }}} */
++
++/* {{{ my_destroy_arg_info_array */
++static void my_destroy_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
++{
++    int i = 0;
++    
++    assert(src != NULL);
++
++    for(i=0; i < num_args; i++) {
++        my_destroy_arg_info(&src[i], deallocate);
++    }
++}
++/* }}} */
++
++/* {{{ my_destroy_arg_info */
++static void my_destroy_arg_info(zend_arg_info* src, apc_free_t deallocate)
++{
++    assert(src != NULL);
++
++    deallocate(src->name);
++    deallocate(src->class_name);
++}
++/* }}} */
++#endif    
++
++/* {{{ my_destroy_class_entry */
++static void my_destroy_class_entry(zend_class_entry* src, apc_free_t deallocate)
++{
++    uint i;
++
++    assert(src != NULL);
++
++    deallocate(src->name);
++#ifndef ZEND_ENGINE_2    
++    deallocate(src->refcount);
++#else
++    if(src->doc_comment) deallocate(src->doc_comment);
++    if(src->filename) deallocate(src->filename);
++#endif
++
++    my_destroy_hashtable(&src->function_table,
++                         (ht_free_fun_t) my_free_function,
++                         deallocate);
++
++    my_destroy_hashtable(&src->default_properties,
++                         (ht_free_fun_t) my_free_zval_ptr,
++                         deallocate);
++
++#ifdef ZEND_ENGINE_2
++    my_destroy_hashtable(&src->properties_info, 
++                            (ht_free_fun_t) my_free_property_info,
++                            deallocate);
++    if(src->static_members) 
++    {
++        my_destroy_hashtable(src->static_members,
++                         (ht_free_fun_t) my_free_zval_ptr,
++                         deallocate);
++        if(src->static_members != &(src->default_static_members))
++        {
++            deallocate(src->static_members);
++        }
++    }
++
++    my_destroy_hashtable(&src->constants_table, 
++                            (ht_free_fun_t) my_free_zval_ptr,
++                            deallocate);
++#endif
++
++    if (src->builtin_functions) {
++        for (i = 0; src->builtin_functions[i].fname != NULL; i++) {
++            my_destroy_function_entry(&src->builtin_functions[i], deallocate);
++        }
++        deallocate(src->builtin_functions);
++    }
++}
++/* }}} */
++
++/* {{{ my_destroy_hashtable */
++static void my_destroy_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
++{
++    int i;
++
++    assert(src != NULL);
++
++    for (i = 0; i < src->nTableSize; i++) {
++        Bucket* p = src->arBuckets[i];
++        while (p != NULL) {
++            Bucket* q = p;
++            p = p->pNext;
++            free_fn(q->pData, deallocate);
++            deallocate(q);
++        }
++    }
++
++    deallocate(src->arBuckets);
++}
++/* }}} */
++
++/* {{{ my_destroy_op_array */
++static void my_destroy_op_array(zend_op_array* src, apc_free_t deallocate)
++{
++    int i;
++
++    assert(src != NULL);
++
++#ifdef ZEND_ENGINE_2
++    if (src->arg_info) {
++        my_free_arg_info_array(src->arg_info, src->num_args, deallocate);
++    }
++#else    
++    if (src->arg_types) {
++        deallocate(src->arg_types);
++    }
++#endif
++
++    deallocate(src->function_name);
++    deallocate(src->filename);
++    deallocate(src->refcount);
++
++    for (i = 0; i < src->last; i++) {
++        my_destroy_zend_op(src->opcodes + i, deallocate);
++    }
++    deallocate(src->opcodes);
++
++    if (src->brk_cont_array) {
++        deallocate(src->brk_cont_array);
++    }
++
++    if (src->static_variables) {
++        my_free_hashtable(src->static_variables,
++                          (ht_free_fun_t) my_free_zval_ptr,
++                          deallocate);
++    }
++    
++#ifdef ZEND_ENGINE_2_1
++    if (src->vars) {
++      for(i=0; i < src->last_var; i++) {
++            if(src->vars[i].name) deallocate(src->vars[i].name);    
++        }
++        deallocate(src->vars);
++    }
++#endif
++#ifdef ZEND_ENGINE_2
++    if(src->try_catch_array) {
++        deallocate(src->try_catch_array);
++    }
++    if (src->doc_comment) {
++        deallocate(src->doc_comment);
++    }
++#endif
++}
++/* }}} */
++
++/* {{{ my_free_zval_ptr */
++static void my_free_zval_ptr(zval** src, apc_free_t deallocate)
++{
++    my_destroy_zval_ptr(src, deallocate);
++    deallocate(src);
++}
++/* }}} */
++
++#ifdef ZEND_ENGINE_2
++/* {{{ my_free_property_info */
++static void my_free_property_info(zend_property_info* src, apc_free_t deallocate)
++{
++    my_destroy_property_info(src, deallocate);
++    deallocate(src);
++}
++/* }}} */
++
++/* {{{ my_free_arg_info_array */
++static void my_free_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
++{
++    my_destroy_arg_info_array(src, num_args, deallocate);
++    deallocate(src);
++}
++/* }}} */
++
++/* {{{ my_free_arg_info */
++static void my_free_arg_info(zend_arg_info* src, apc_free_t deallocate)
++{
++    my_destroy_arg_info(src, deallocate);
++    deallocate(src);
++}
++/* }}} */
++#endif
++
++/* {{{ my_free_function */
++static void my_free_function(zend_function* src, apc_free_t deallocate)
++{
++    my_destroy_function(src, deallocate);
++    deallocate(src);
++}
++/* }}} */
++
++/* {{{ my_free_hashtable */
++static void my_free_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
++{
++    my_destroy_hashtable(src, free_fn, deallocate);
++    deallocate(src);
++}
++/* }}} */
++
++/* {{{ apc_free_op_array */
++void apc_free_op_array(zend_op_array* src, apc_free_t deallocate)
++{
++    if (src != NULL) {
++        my_destroy_op_array(src, deallocate);
++        deallocate(src);
++    }
++}
++/* }}} */
++
++/* {{{ apc_free_functions */
++void apc_free_functions(apc_function_t* src, apc_free_t deallocate)
++{
++    int i;
++
++    if (src != NULL) {
++        for (i = 0; src[i].function != NULL; i++) {
++            deallocate(src[i].name);
++            my_destroy_function(src[i].function, deallocate);
++            deallocate(src[i].function);
++        }   
++        deallocate(src);
++    }   
++}
++/* }}} */
++
++/* {{{ apc_free_classes */
++void apc_free_classes(apc_class_t* src, apc_free_t deallocate)
++{
++    int i;
++
++    if (src != NULL) {
++        for (i = 0; src[i].class_entry != NULL; i++) {
++            deallocate(src[i].name);
++            deallocate(src[i].parent_name);
++            my_destroy_class_entry(src[i].class_entry, deallocate);
++            deallocate(src[i].class_entry);
++        }   
++        deallocate(src);
++    }   
++}
++/* }}} */
++
++/* {{{ apc_free_zval */
++void apc_free_zval(zval* src, apc_free_t deallocate)
++{
++    if (src != NULL) {
++        if(my_destroy_zval(src, deallocate) == SUCCESS) {
++            deallocate(src);
++        }
++    }
++}
++/* }}} */
++
++
++/* Used only by my_prepare_op_array_for_execution */
++#define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION()                                                \
++                         /* The fetch is only required if auto_globals_jit=1  */                \
++                        if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&                            \
++                            zo->op1.op_type == IS_CONST &&                                      \
++                            zo->op1.u.constant.type == IS_STRING &&                             \
++                            zo->op1.u.constant.value.str.val[0] == '_') {                       \
++                                                                                                \
++                            znode* varname = &zo->op1;                                          \
++                            (void)zend_is_auto_global(varname->u.constant.value.str.val,        \
++                                                          varname->u.constant.value.str.len     \
++                                                          TSRMLS_CC);                           \
++                        }                                                                       \
++
++/* {{{ my_prepare_op_array_for_execution */
++static int my_prepare_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC) 
++{
++    /* combine my_fetch_global_vars and my_copy_data_exceptions.
++     *   - Pre-fetch superglobals which would've been pre-fetched in parse phase.
++     *   - If the opcode stream contain mutable data, ensure a copy.
++     *   - Fixup array jumps in the same loop.
++     */
++    int i=src->last;
++    zend_op *zo;
++    zend_op *dzo;
++#ifdef ZEND_ENGINE_2
++    apc_opflags_t * flags = APCG(reserved_offset) != -1 ? 
++                                (apc_opflags_t*) & (src->reserved[APCG(reserved_offset)]) : NULL;
++    int needcopy = flags ? flags->deep_copy : 1;
++    /* auto_globals_jit was not in php4 */
++    int do_prepare_fetch_global = PG(auto_globals_jit) && (flags == NULL || flags->unknown_global);
++
++#define FETCH_AUTOGLOBAL(member) do { \
++    if(flags && flags->member == 1) { \
++        zend_is_auto_global(#member,\
++                            (sizeof(#member) - 1)\
++                            TSRMLS_CC);\
++    } \
++}while(0); 
++            
++    FETCH_AUTOGLOBAL(_GET);
++    FETCH_AUTOGLOBAL(_POST);
++    FETCH_AUTOGLOBAL(_COOKIE);
++    FETCH_AUTOGLOBAL(_SERVER);
++    FETCH_AUTOGLOBAL(_ENV);
++    FETCH_AUTOGLOBAL(_FILES);
++    FETCH_AUTOGLOBAL(_REQUEST);
++
++#else
++    int needcopy = 0;
++    int do_prepare_fetch_global = 0;
++    int j = 0;
++
++    for(j = 0; j < src->last; j++) {
++        zo = &src->opcodes[j];
++        
++        if( ((zo->op1.op_type == IS_CONST &&
++              zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||  
++            ((zo->op2.op_type == IS_CONST &&
++              zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
++            needcopy = 1;
++        }
++    }
++#endif
++    
++    if(needcopy) {
++
++        dst->opcodes = (zend_op*) apc_xmemcpy(src->opcodes, 
++                                    sizeof(zend_op) * src->last,
++                                    apc_php_malloc);
++        zo = src->opcodes;
++        dzo = dst->opcodes;
++        while(i > 0) {
++
++            if( ((zo->op1.op_type == IS_CONST &&
++                  zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||  
++                ((zo->op2.op_type == IS_CONST &&
++                  zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
++
++                if(!(my_copy_zend_op(dzo, zo, apc_php_malloc, apc_php_free))) {
++                    assert(0); /* emalloc failed or a bad constant array */
++                }
++            }
++            
++#ifdef ZEND_ENGINE_2
++            switch(zo->opcode) {
++                case ZEND_JMP:
++                    dzo->op1.u.jmp_addr = dst->opcodes + 
++                                            (zo->op1.u.jmp_addr - src->opcodes);
++                    break;
++                case ZEND_JMPZ:
++                case ZEND_JMPNZ:
++                case ZEND_JMPZ_EX:
++                case ZEND_JMPNZ_EX:
++                    dzo->op2.u.jmp_addr = dst->opcodes + 
++                                            (zo->op2.u.jmp_addr - src->opcodes);
++                    break;
++                case ZEND_FETCH_R:
++                case ZEND_FETCH_W:
++                case ZEND_FETCH_IS:
++                case ZEND_FETCH_FUNC_ARG:
++                    if(do_prepare_fetch_global)
++                    {
++                        APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
++                    }
++                    break;
++                default:
++                    break;
++            }
++#endif
++            i--;
++            zo++;
++            dzo++;
++        }
++#ifdef ZEND_ENGINE_2
++    } else {  /* !needcopy */
++        /* The fetch is only required if auto_globals_jit=1  */
++        if(do_prepare_fetch_global)
++        {
++            zo = src->opcodes;
++            while(i > 0) {
++
++                if(zo->opcode == ZEND_FETCH_R || 
++                   zo->opcode == ZEND_FETCH_W ||
++                   zo->opcode == ZEND_FETCH_IS ||
++                   zo->opcode == ZEND_FETCH_FUNC_ARG 
++                  ) {
++                    APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
++                }
++
++                i--;
++                zo++;
++            }
++        }
++#endif
++    }
++    return 1;
++}
++/* }}} */
++
++/* {{{ apc_copy_op_array_for_execution */
++zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC)
++{
++    if(dst == NULL) {
++        dst = (zend_op_array*) emalloc(sizeof(src[0]));
++    }
++    memcpy(dst, src, sizeof(src[0]));
++    dst->static_variables = my_copy_static_variables(src, apc_php_malloc, apc_php_free);
++
++    dst->refcount = apc_xmemcpy(src->refcount,
++                                      sizeof(src->refcount[0]),
++                                      apc_php_malloc);
++    
++    my_prepare_op_array_for_execution(dst,src TSRMLS_CC);
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ apc_copy_function_for_execution */
++zend_function* apc_copy_function_for_execution(zend_function* src)
++{
++    zend_function* dst;
++    TSRMLS_FETCH();
++
++    dst = (zend_function*) emalloc(sizeof(src[0]));
++    memcpy(dst, src, sizeof(src[0]));
++    apc_copy_op_array_for_execution(&(dst->op_array), &(src->op_array) TSRMLS_CC);
++    return dst;
++}
++/* }}} */
++
++/* {{{ apc_copy_function_for_execution_ex */
++zend_function* apc_copy_function_for_execution_ex(void *dummy, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
++{
++    if(src->type==ZEND_INTERNAL_FUNCTION || src->type==ZEND_OVERLOADED_FUNCTION) return src;
++    return apc_copy_function_for_execution(src);
++}
++/* }}} */
++
++/* {{{ apc_copy_class_entry_for_execution */
++zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived)
++{
++    zend_class_entry* dst = (zend_class_entry*) emalloc(sizeof(src[0]));
++    memcpy(dst, src, sizeof(src[0]));
++
++#ifdef ZEND_ENGINE_2
++    if(src->num_interfaces)
++    {
++        /* These are slots to be populated later by ADD_INTERFACE insns */
++        dst->interfaces = apc_php_malloc(
++                            sizeof(zend_class_entry*) * src->num_interfaces);
++        memset(dst->interfaces, 0, 
++                            sizeof(zend_class_entry*) * src->num_interfaces);
++    }
++    else
++    {
++        /* assert(dst->interfaces == NULL); */
++    }
++#endif
++
++#ifndef ZEND_ENGINE_2    
++    dst->refcount = apc_xmemcpy(src->refcount,
++                                      sizeof(src->refcount[0]),
++                                      apc_php_malloc);
++#endif        
++
++    /* Deep-copy the class properties, because they will be modified */
++
++    my_copy_hashtable(&dst->default_properties,
++                      &src->default_properties,
++                      (ht_copy_fun_t) my_copy_zval_ptr,
++                      (ht_free_fun_t) my_free_zval_ptr,
++                      1,
++                      apc_php_malloc, apc_php_free);
++
++    /* For derived classes, we must also copy the function hashtable (although
++     * we can merely bitwise copy the functions it contains) */
++
++    my_copy_hashtable(&dst->function_table,
++                      &src->function_table,
++                      (ht_copy_fun_t) apc_copy_function_for_execution_ex,
++                      NULL,
++                      0,
++                      apc_php_malloc, apc_php_free);
++#ifdef ZEND_ENGINE_2
++    my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function_for_execution, src, dst);
++
++    /* zend_do_inheritance merges properties_info.
++     * Need only shallow copying as it doesn't hold the pointers.
++     */
++    my_copy_hashtable(&dst->properties_info,
++                      &src->properties_info,
++                      (ht_copy_fun_t) my_copy_property_info_for_execution,
++                      NULL,
++                      0,
++                      apc_php_malloc, apc_php_free);
++
++#ifdef ZEND_ENGINE_2_2
++    /* php5.2 introduced a scope attribute for property info */
++    my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
++#endif
++
++    /* if inheritance results in a hash_del, it might result in
++     * a pefree() of the pointers here. Deep copying required. 
++     */
++
++    my_copy_hashtable(&dst->constants_table,
++                      &src->constants_table,
++                      (ht_copy_fun_t) my_copy_zval_ptr,
++                      NULL,
++                      1,
++                      apc_php_malloc, apc_php_free);
++
++    my_copy_hashtable(&dst->default_static_members,
++                      &src->default_static_members,
++                      (ht_copy_fun_t) my_copy_zval_ptr,
++                      (ht_free_fun_t) my_free_zval_ptr,
++                      1,
++                      apc_php_malloc, apc_php_free);
++
++    if(src->static_members != &(src->default_static_members))
++    {
++        dst->static_members = my_copy_hashtable(NULL,
++                          src->static_members,
++                          (ht_copy_fun_t) my_copy_zval_ptr,
++                          (ht_free_fun_t) my_free_zval_ptr,
++                          1,
++                          apc_php_malloc, apc_php_free);
++    }
++    else 
++    {
++        dst->static_members = &(dst->default_static_members);
++    }
++
++#endif
++
++    return dst;
++}
++/* }}} */
++
++/* {{{ apc_free_class_entry_after_execution */
++void apc_free_class_entry_after_execution(zend_class_entry* src)
++{
++#ifdef ZEND_ENGINE_2
++    if(src->num_interfaces > 0 && src->interfaces) {
++        apc_php_free(src->interfaces);
++        src->interfaces = NULL;
++        src->num_interfaces = 0;
++    }
++    /* my_destroy_hashtable() does not play nice with refcounts */
++
++    zend_hash_clean(&src->default_static_members);
++    if(src->static_members != &(src->default_static_members))
++    {
++        zend_hash_destroy(src->static_members);
++        apc_php_free(src->static_members);
++        src->static_members = NULL;
++    }
++    else
++    {
++        src->static_members = NULL;
++    }
++    zend_hash_clean(&src->default_properties);
++    zend_hash_clean(&src->constants_table);
++#endif
++
++    /* TODO: more cleanup */
++}
++/* }}} */
++
++#ifdef ZEND_ENGINE_2
++
++/* {{{ my_fixup_function */
++static void my_fixup_function(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
++{
++    zend_function* zf = p->pData;
++
++    #define SET_IF_SAME_NAME(member) \
++    do { \
++        if(src->member && !strcmp(zf->common.function_name, src->member->common.function_name)) { \
++            dst->member = zf; \
++        } \
++    } \
++    while(0)
++
++    if(zf->common.scope == src)
++    {
++    
++        /* Fixing up the default functions for objects here since
++         * we need to compare with the newly allocated functions
++         *
++         * caveat: a sub-class method can have the same name as the
++         * parent's constructor and create problems.
++         */
++        
++        if(zf->common.fn_flags & ZEND_ACC_CTOR) dst->constructor = zf;
++        else if(zf->common.fn_flags & ZEND_ACC_DTOR) dst->destructor = zf;
++        else if(zf->common.fn_flags & ZEND_ACC_CLONE) dst->clone = zf;
++        else
++        {
++            SET_IF_SAME_NAME(__get);
++            SET_IF_SAME_NAME(__set);
++            SET_IF_SAME_NAME(__unset);
++            SET_IF_SAME_NAME(__isset);
++            SET_IF_SAME_NAME(__call);
++#ifdef ZEND_ENGINE_2_2
++            SET_IF_SAME_NAME(__tostring);
++#endif
++        }
++        zf->common.scope = dst;
++    }
++    else
++    {
++        /* no other function should reach here */
++        assert(0);
++    }
++
++    #undef SET_IF_SAME_NAME
++}
++/* }}} */
++
++#ifdef ZEND_ENGINE_2_2
++/* {{{ my_fixup_property_info */
++static void my_fixup_property_info(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
++{
++    zend_property_info* property_info = (zend_property_info*)p->pData;
++
++    if(property_info->ce == src)
++    {
++        property_info->ce = dst;
++    }
++    else
++    {
++        assert(0); /* should never happen */
++    }
++}
++/* }}} */
++#endif
++
++/* {{{ my_fixup_hashtable */
++static void my_fixup_hashtable(HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst)
++{
++    Bucket *p;
++    
++      uint i;
++    
++      for (i = 0; i < ht->nTableSize; i++) {
++              if(!ht->arBuckets) break;
++        p = ht->arBuckets[i];
++              while (p != NULL) {
++            fixup(p, src, dst);
++                      p = p->pNext;
++              }
++      }
++}
++/* }}} */
++
++#endif
++
++/* {{{ my_check_copy_function */
++static int my_check_copy_function(Bucket* p, va_list args)
++{
++    zend_class_entry* src = va_arg(args, zend_class_entry*);
++    zend_function* zf = (zend_function*)p->pData;
++#ifndef ZEND_ENGINE_2
++    zend_class_entry* parent = src->parent;
++    zend_function* parent_fn = NULL;
++#endif
++
++#ifdef ZEND_ENGINE_2
++    return (zf->common.scope == src);
++#else
++      if (parent &&
++        zend_hash_quick_find(&parent->function_table, p->arKey, 
++            p->nKeyLength, p->h, (void **) &parent_fn)==SUCCESS) {
++        
++        if((parent_fn && zf) && 
++                (parent_fn->op_array.refcount == zf->op_array.refcount))
++        {
++            return 0;
++        }
++    }
++    return 1;
++#endif 
++}
++/* }}} */
++
++/* {{{ my_check_copy_default_property */
++static int my_check_copy_default_property(Bucket* p, va_list args)
++{
++    zend_class_entry* src = va_arg(args, zend_class_entry*);
++    zend_class_entry* parent = src->parent;
++    zval ** child_prop = (zval**)p->pData;
++    zval ** parent_prop = NULL;
++
++      if (parent &&
++        zend_hash_quick_find(&parent->default_properties, p->arKey, 
++            p->nKeyLength, p->h, (void **) &parent_prop)==SUCCESS) {
++
++        if((parent_prop && child_prop) && (*parent_prop) == (*child_prop))
++        {
++            return 0;
++        }
++    }
++    
++    /* possibly not in the parent */
++    return 1;
++}
++/* }}} */
++
++#ifdef ZEND_ENGINE_2
++
++/* {{{ my_check_copy_property_info */
++static int my_check_copy_property_info(Bucket* p, va_list args)
++{
++    zend_class_entry* src = va_arg(args, zend_class_entry*);
++    zend_class_entry* parent = src->parent;
++    zend_property_info* child_info = (zend_property_info*)p->pData;
++    zend_property_info* parent_info = NULL;
++
++#ifdef ZEND_ENGINE_2_2
++    /* so much easier */
++    return (child_info->ce == src);
++#endif
++
++      if (parent &&
++        zend_hash_quick_find(&parent->properties_info, p->arKey, p->nKeyLength, 
++            p->h, (void **) &parent_info)==SUCCESS) {
++        if(parent_info->flags & ZEND_ACC_PRIVATE)
++        {
++            return 1;
++        }
++        if((parent_info->flags & ZEND_ACC_PPP_MASK) != 
++            (child_info->flags & ZEND_ACC_PPP_MASK))
++        {
++            /* TODO: figure out whether ACC_CHANGED is more appropriate
++             * here */
++            return 1;
++        }
++        return 0;
++    }
++    
++    /* property doesn't exist in parent, copy into cached child */
++    return 1;
++}
++/* }}} */
++
++/* {{{ my_check_copy_static_member */
++static int my_check_copy_static_member(Bucket* p, va_list args)
++{
++    zend_class_entry* src = va_arg(args, zend_class_entry*);
++    HashTable * ht = va_arg(args, HashTable*);
++    zend_class_entry* parent = src->parent;
++    HashTable * parent_ht = NULL;
++    char * member_name;
++    char * class_name = NULL;
++
++    zend_property_info *parent_info = NULL;
++    zend_property_info *child_info = NULL;
++    zval ** parent_prop = NULL;
++    zval ** child_prop = (zval**)(p->pData);
++
++    if(!parent) {
++        return 1;
++    }
++
++    /* these do not need free'ing */
++#ifdef ZEND_ENGINE_2_2
++    zend_unmangle_property_name(p->arKey, p->nKeyLength-1, &class_name, &member_name);
++#else
++    zend_unmangle_property_name(p->arKey, &class_name, &member_name);
++#endif
++
++    /* please refer do_inherit_property_access_check in zend_compile.c
++     * to understand why we lookup in properties_info.
++     */
++    if((zend_hash_find(&parent->properties_info, member_name, 
++                        strlen(member_name)+1, (void**)&parent_info) == SUCCESS)
++        &&
++        (zend_hash_find(&src->properties_info, member_name,
++                        strlen(member_name)+1, (void**)&child_info) == SUCCESS))
++    {
++        if(child_info->flags & ZEND_ACC_STATIC &&    
++            (parent_info->flags & ZEND_ACC_PROTECTED &&
++            child_info->flags & ZEND_ACC_PUBLIC))
++        {
++            /* Do not copy into static_members. zend_do_inheritance
++             * will automatically insert a NULL value.
++             * TODO: decrement refcount or fixup when copying out for exec ? 
++             */ 
++            return 0;
++        }
++        if(ht == &(src->default_static_members))
++        {
++            parent_ht = &parent->default_static_members;
++        }
++        else
++        {
++            parent_ht = parent->static_members;
++        }
++
++        if(zend_hash_quick_find(parent_ht, p->arKey,
++                       p->nKeyLength, p->h, (void**)&parent_prop) == SUCCESS)
++        {
++            /* they point to the same zval */
++            if(*parent_prop == *child_prop)
++            {
++                return 0;
++            }
++        }
++    }
++    
++    return 1;
++}
++/* }}} */
++#endif
++
++/* {{{ apc_register_optimizer(apc_optimize_function_t optimizer)
++ *      register a optimizer callback function, returns the previous callback
++ */
++apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC) {
++    apc_optimize_function_t old_optimizer = APCG(apc_optimize_function);
++    APCG(apc_optimize_function) = optimizer;
++    return old_optimizer;
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_compile.h php-5.1.6/ext/APC/apc_compile.h
+--- php-5.1.6.old/ext/apc/apc_compile.h        1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_compile.h    2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,134 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
++  |          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_compile.h,v 3.19 2007/03/08 22:03:35 gopalv Exp $ */
++
++#ifndef APC_COMPILE_H
++#define APC_COMPILE_H
++
++/*
++ * This module encapsulates most of the complexity involved in deep-copying
++ * the Zend compiler data structures. The routines are allocator-agnostic, so
++ * the same function can be used for copying to and from shared memory.
++ */
++
++#include "apc.h"
++#include "apc_php.h"
++
++/* {{{ struct definition: apc_function_t */
++typedef struct apc_function_t apc_function_t;
++struct apc_function_t {
++    char* name;                 /* the function name */
++    int name_len;               /* length of name */
++    zend_function* function;    /* the zend function data structure */
++};
++/* }}} */
++
++/* {{{ struct definition: apc_class_t */
++typedef struct apc_class_t apc_class_t;
++struct apc_class_t {
++    char* name;                     /* the class name */
++    int name_len;                   /* length of name */
++    int is_derived;                 /* true if this is a derived class */
++    char* parent_name;              /* the parent class name */
++    zend_class_entry* class_entry;  /* the zend class data structure */
++};
++/* }}} */
++
++/* {{{ struct definition: apc_opflags_t */
++typedef struct apc_opflags_t apc_opflags_t;
++struct apc_opflags_t {
++    unsigned int has_jumps      : 1; /* has jump offsets */
++    unsigned int deep_copy      : 1; /* needs deep copy */
++
++    /* autoglobal bits */
++    unsigned int _POST          : 1;
++    unsigned int _GET           : 1;
++    unsigned int _COOKIE        : 1;
++    unsigned int _SERVER        : 1;
++    unsigned int _ENV           : 1;
++    unsigned int _FILES         : 1;
++    unsigned int _REQUEST       : 1;
++    unsigned int unknown_global : 1;
++};
++/* }}} */
++
++/*
++ * These are the top-level copy functions.
++ */
++
++extern zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC);
++extern zend_class_entry* apc_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate);
++extern apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC);
++extern apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC);
++extern zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate);
++
++/*
++ * Deallocation functions corresponding to the copy functions above.
++ */
++
++extern void apc_free_op_array(zend_op_array* src, apc_free_t deallocate);
++extern void apc_free_functions(apc_function_t* src, apc_free_t deallocate);
++extern void apc_free_classes(apc_class_t* src, apc_free_t deallocate);
++extern void apc_free_zval(zval* src, apc_free_t deallocate);
++
++/*
++ * These "copy-for-execution" functions must be called after retrieving an
++ * object from the shared cache. They do the minimal amount of work necessary
++ * to allow multiple processes to concurrently execute the same VM data
++ * structures.
++ */
++
++extern zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC);
++extern zend_function* apc_copy_function_for_execution(zend_function* src);
++extern zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived);
++
++/*
++ * The "free-after-execution" function performs a cursory clean up of the class data
++ * This is required to minimize memory leak warnings and to ensure correct destructor
++ * ordering of some variables.
++ */
++extern void apc_free_class_entry_after_execution(zend_class_entry* src);
++
++/*
++ * Optimization callback definition and registration function. 
++ */
++typedef zend_op_array* (*apc_optimize_function_t) (zend_op_array* TSRMLS_DC);
++extern apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC);
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_debug.c php-5.1.6/ext/APC/apc_debug.c
+--- php-5.1.6.old/ext/apc/apc_debug.c  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_debug.c      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,57 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
++  |          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_debug.c,v 3.6 2006/12/07 23:51:28 gopalv Exp $ */
++#include "apc.h"
++#include <stdio.h>
++#include "zend_compile.h"
++
++#ifdef __DEBUG_APC__
++
++#include <dlfcn.h>
++
++/* keep track of vld_dump_oparray() signature */
++typedef void (*vld_dump_f) (zend_op_array * TSRMLS_DC);
++
++#endif
++
++void dump(zend_op_array *op_array TSRMLS_DC)
++{
++#ifdef __DEBUG_APC__
++      vld_dump_f dump_op_array = dlsym(NULL, "vld_dump_oparray");
++
++      if(dump_op_array)
++      {
++              dump_op_array(op_array TSRMLS_CC); 
++      }
++      else
++      {
++              apc_wprint("vld is not installed or something even worse.");
++      }
++#endif
++}
+diff -ruN php-5.1.6.old/ext/apc/apc_debug.h php-5.1.6/ext/APC/apc_debug.h
+--- php-5.1.6.old/ext/apc/apc_debug.h  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_debug.h      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1 @@
++void dump(zend_op_array * TSRMLS_DC);
+diff -ruN php-5.1.6.old/ext/apc/apc.dsp php-5.1.6/ext/APC/apc.dsp
+--- php-5.1.6.old/ext/apc/apc.dsp      1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc.dsp  2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,207 @@
++# Microsoft Developer Studio Project File - Name="apc" - Package Owner=<4>
++# Microsoft Developer Studio Generated Build File, Format Version 6.00
++# ** DO NOT EDIT **
++
++# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
++
++CFG=apc - Win32 Debug_TS
++!MESSAGE This is not a valid makefile. To build this project using NMAKE,
++!MESSAGE use the Export Makefile command and run
++!MESSAGE 
++!MESSAGE NMAKE /f "apc.mak".
++!MESSAGE 
++!MESSAGE You can specify a configuration when running NMAKE
++!MESSAGE by defining the macro CFG on the command line. For example:
++!MESSAGE 
++!MESSAGE NMAKE /f "apc.mak" CFG="apc - Win32 Debug_TS"
++!MESSAGE 
++!MESSAGE Possible choices for configuration are:
++!MESSAGE 
++!MESSAGE "apc - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
++!MESSAGE "apc - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
++!MESSAGE 
++
++# Begin Project
++# PROP AllowPerConfigDependencies 0
++# PROP Scc_ProjName ""
++# PROP Scc_LocalPath ""
++CPP=cl.exe
++MTL=midl.exe
++RSC=rc.exe
++
++!IF  "$(CFG)" == "apc - Win32 Debug_TS"
++
++# PROP BASE Use_MFC 0
++# PROP BASE Use_Debug_Libraries 1
++# PROP BASE Output_Dir "Debug_TS"
++# PROP BASE Intermediate_Dir "Debug_TS"
++# PROP BASE Target_Dir ""
++# PROP Use_MFC 0
++# PROP Use_Debug_Libraries 1
++# PROP Output_Dir "Debug_TS"
++# PROP Intermediate_Dir "Debug_TS"
++# PROP Ignore_Export_Lib 0
++# PROP Target_Dir ""
++# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /GZ /c
++# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\php4" /I "..\..\..\php4\main" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\win32" /I "..\..\..\php4\regex" /D "TSRM_LOCKS" /D HAVE_APC=1 /D "COMPILE_DL_APC" /D ZEND_DEBUG=1 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /GZ /c
++# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
++# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
++# ADD BASE RSC /l 0x409 /d "_DEBUG"
++# ADD RSC /l 0x409 /d "_DEBUG"
++BSC32=bscmake.exe
++# ADD BASE BSC32 /nologo
++# ADD BSC32 /nologo
++LINK32=link.exe
++# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
++# ADD LINK32 php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug_TS/php_apc.dll" /pdbtype:sept /libpath:"..\..\..\php4\Debug_TS"
++
++!ELSEIF  "$(CFG)" == "apc - Win32 Release_TS"
++
++# PROP BASE Use_MFC 0
++# PROP BASE Use_Debug_Libraries 0
++# PROP BASE Output_Dir "Release_TS"
++# PROP BASE Intermediate_Dir "Release_TS"
++# PROP BASE Target_Dir ""
++# PROP Use_MFC 0
++# PROP Use_Debug_Libraries 0
++# PROP Output_Dir "Release_TS"
++# PROP Intermediate_Dir "Release_TS"
++# PROP Ignore_Export_Lib 0
++# PROP Target_Dir ""
++# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /c
++# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\php4" /I "..\..\..\php4\main" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\win32" /I "..\..\..\php4\regex" /D "TSRM_LOCKS" /D HAVE_APC=1 /D "COMPILE_DL_APC" /D ZEND_DEBUG=0 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /c
++# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
++# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
++# ADD BASE RSC /l 0x409 /d "NDEBUG"
++# ADD RSC /l 0x409 /d "NDEBUG"
++BSC32=bscmake.exe
++# ADD BASE BSC32 /nologo
++# ADD BSC32 /nologo
++LINK32=link.exe
++# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
++# ADD LINK32 php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../Release_TS/php_apc.dll" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\php4\Release_TS_Inline"
++
++!ENDIF 
++
++# Begin Target
++
++# Name "apc - Win32 Debug_TS"
++# Name "apc - Win32 Release_TS"
++# Begin Group "Source Files"
++
++# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
++# Begin Source File
++
++SOURCE=.\apc.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_cache.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_compile.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_debug.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_fcntl_win32.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_main.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_rfc1867.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_shm.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_sma.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_stack.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_zend.c
++# End Source File
++# Begin Source File
++
++SOURCE=.\php_apc.c
++# End Source File
++# End Group
++# Begin Group "Header Files"
++
++# PROP Default_Filter "h;hpp;hxx;hm;inl"
++# Begin Source File
++
++SOURCE=.\apc.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_cache.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_compile.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_debug.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_fcntl.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_globals.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_lock.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_main.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_php.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_shm.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_sma.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_stack.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\apc_zend.h
++# End Source File
++# Begin Source File
++
++SOURCE=.\php_apc.h
++# End Source File
++# End Group
++# Begin Group "Resource Files"
++
++# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
++# End Group
++# End Target
++# End Project
+diff -ruN php-5.1.6.old/ext/apc/apc_fcntl.c php-5.1.6/ext/APC/apc_fcntl.c
+--- php-5.1.6.old/ext/apc/apc_fcntl.c  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_fcntl.c      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,118 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: George Schlossnagle <george@omniti.com>                     |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  +----------------------------------------------------------------------+
++
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
++
++   All other licensing and usage conditions are those of the PHP Group.
++
++ */
++
++/* $Id: apc_fcntl.c,v 3.25 2006/06/19 02:52:49 rasmus Exp $ */
++
++#include "apc_fcntl.h"
++#include "apc.h"
++#include <unistd.h>
++#include <fcntl.h>
++
++int apc_fcntl_create(const char* pathname)
++{
++    int fd;
++    if(pathname == NULL) {
++        char lock_path[] = "/tmp/.apc.XXXXXX";
++        mktemp(lock_path);
++        fd = open(lock_path, O_RDWR|O_CREAT, 0666);
++        if(fd > 0 ) {
++            unlink(lock_path);
++            return fd;
++        } else {
++            apc_eprint("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", lock_path);
++            return -1;
++        }
++    }
++    fd = open(pathname, O_RDWR|O_CREAT, 0666);
++    if(fd > 0 ) {
++        unlink(pathname);
++        return fd;
++    }
++    apc_eprint("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
++    return -1;
++}
++
++void apc_fcntl_destroy(int fd)
++{
++    close(fd);
++}
++
++static int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
++{
++  int ret;
++  struct flock lock;
++
++  lock.l_type = type;
++  lock.l_start = offset;
++  lock.l_whence = whence;
++  lock.l_len = len;
++  lock.l_pid = 0;
++
++  do { ret = fcntl(fd, cmd, &lock) ; }
++  while(ret < 0 && errno == EINTR);
++  return(ret);
++}
++
++void apc_fcntl_lock(int fd)
++{
++    if(lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
++        apc_eprint("apc_fcntl_lock failed:");
++    }
++}
++
++void apc_fcntl_rdlock(int fd)
++{
++    if(lock_reg(fd, F_SETLKW, F_RDLCK, 0, SEEK_SET, 0) < 0) {
++        apc_eprint("apc_fcntl_rdlock failed:");
++    }
++}
++
++zend_bool apc_fcntl_nonblocking_lock(int fd)
++{
++    if(lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0) {
++        if(errno==EACCES||errno==EAGAIN) return 0;
++        else apc_eprint("apc_fcntl_lock failed:");
++    }
++    return 1;
++}
++
++void apc_fcntl_unlock(int fd)
++{
++    if(lock_reg(fd, F_SETLKW, F_UNLCK, 0, SEEK_SET, 0) < 0) {
++        apc_eprint("apc_fcntl_unlock failed:");
++    }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_fcntl.h php-5.1.6/ext/APC/apc_fcntl.h
+--- php-5.1.6.old/ext/apc/apc_fcntl.h  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_fcntl.h      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,50 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt.                                 |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: George Schlossnagle <george@omniti.com>                     |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  +----------------------------------------------------------------------+
++
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
++
++   All other licensing and usage conditions are those of the PHP Group.
++
++ */
++
++/* $Id: apc_fcntl.h,v 3.14 2006/05/31 22:24:48 rasmus Exp $ */
++
++#ifndef APC_FCNTL_H
++#define APC_FCNTL_H
++
++
++extern int apc_fcntl_create(const char* pathname);
++extern void apc_fcntl_destroy(int fd);
++extern void apc_fcntl_lock(int fd);
++extern void apc_fcntl_rdlock(int fd);
++extern void apc_fcntl_unlock(int fd);
++extern unsigned char apc_fcntl_nonblocking_lock(int fd);
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_fcntl_win32.c php-5.1.6/ext/APC/apc_fcntl_win32.c
+--- php-5.1.6.old/ext/apc/apc_fcntl_win32.c    1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_fcntl_win32.c        2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,117 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: George Schlossnagle <george@omniti.com>                     |
++  |          Edin Kadribasic <edink@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_fcntl_win32.c,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */
++
++#include "apc_fcntl.h"
++#include "apc.h"
++#include <php.h>
++#include <win32/flock.h>
++#include <io.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++
++int apc_fcntl_create(const char* pathname)
++{
++      char *lock_file = emalloc(MAXPATHLEN);
++      HANDLE fd;
++      DWORD tmplen;
++      static int i=0;
++      
++      tmplen = GetTempPath(MAXPATHLEN, lock_file);
++      if (!tmplen) {
++              efree(lock_file);
++              return -1;
++      }
++
++      snprintf(lock_file + tmplen, MAXPATHLEN - tmplen - 1, "apc.lock.%d", i++);
++      
++      fd = CreateFile(lock_file,
++        GENERIC_READ | GENERIC_WRITE,
++        FILE_SHARE_READ | FILE_SHARE_WRITE,
++        NULL,
++        OPEN_ALWAYS,
++        FILE_ATTRIBUTE_NORMAL,
++        NULL);
++        
++
++      if (fd == INVALID_HANDLE_VALUE) {
++              apc_eprint("apc_fcntl_create: could not open %s", lock_file);
++              efree(lock_file);
++              return -1;
++      }
++      
++      efree(lock_file);
++      return (int)fd;
++}
++
++void apc_fcntl_destroy(int fd)
++{
++      CloseHandle((HANDLE)fd);
++}
++
++void apc_fcntl_lock(int fd)
++{
++      OVERLAPPED offset =     {0, 0, 0, 0, NULL};
++      
++      if (!LockFileEx((HANDLE)fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &offset)) {
++              apc_eprint("apc_fcntl_lock failed errno:%d", GetLastError());
++      }
++}
++
++void apc_fcntl_rdlock(int fd)
++{
++      OVERLAPPED offset =     {0, 0, 0, 0, NULL};
++      
++      if (!LockFileEx((HANDLE)fd, 0, 0, 1, 0, &offset)) {
++              apc_eprint("apc_fcntl_rdlock failed errno:%d", GetLastError());
++      }
++}
++
++void apc_fcntl_unlock(int fd)
++{
++      OVERLAPPED offset =     {0, 0, 0, 0, NULL};
++
++      if (!UnlockFileEx((HANDLE)fd, 0, 1, 0, &offset)) {
++              DWORD error_code = GetLastError();
++              /* Ignore already unlocked error */
++              if (error_code != ERROR_NOT_LOCKED) {
++                      apc_eprint("apc_fcntl_unlock failed errno:%d", error_code);
++              }
++      }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_futex.c php-5.1.6/ext/APC/apc_futex.c
+--- php-5.1.6.old/ext/apc/apc_futex.c  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_futex.c      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,116 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Brian Shire <shire@php.net>                                 |
++  +----------------------------------------------------------------------+
++
++ */
++
++/* $Id: apc_futex.c,v 3.2 2006/10/12 08:23:16 shire Exp $ */
++
++/***************************************************************************
++* Futex (Fast Userspace Mutex) support for APC
++* 
++* Futex support provides user space locking with system calls only
++* for the contended cases.  Some required reading for this functionality is:
++*
++* 'Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux' 
++*  by Hubertus Franke, Rusty Russell, and Matthew Kirkwood
++*   http://www.realitydiluted.com/nptl-uclibc/docs/futex.pdf
++*
++* 'Futexes are Tricky' by Ulrich Drepper 
++*    http://people.redhat.com/drepper/futex.pdf
++*
++* 
++* This implementation is optimized and designed for the i386 and x86_64 
++* architectures.  Other architectures may require additional design 
++* to efficiently and safely implement this functionality. 
++*
++* Lock values are:
++* 0 = Unlocked
++* 1 = Locked without any waiting processes
++* 2 = Locked with an unknown number of waiting processes
++*
++***************************************************************************/
++
++#include "apc.h"
++#include "apc_futex.h"
++
++#ifdef APC_FUTEX_LOCKS
++
++
++inline int apc_futex_create()
++{
++    return 0;
++}
++
++inline void apc_futex_destroy(volatile int* lock)
++{
++    return;
++}
++
++void apc_futex_lock(volatile int* lock)
++{
++    int c;
++  
++    /*  Attempt to obtain a lock if not currently locked.  If the previous
++     *  value was not 0 then we did not obtain the lock, and must wait.
++     *  If the previous value was 1 (has no waiting processes) then we
++     *  set the lock to 2 before blocking on the futex wait operation.  
++     *  This implementation suffers from the possible difficulty of 
++     *  efficently implementing the atomic xchg operation on some
++     *  architectures, and could also cause unecessary wake operations by
++     *  setting the lock to 2 when there are no additional waiters.
++     */ 
++    if((c = apc_cmpxchg(lock, 0, 1)) != 0) {
++        if(c != 2) {
++            c = apc_xchg(lock, 2);
++        }
++        while(c != 0) {
++            apc_futex_wait(lock, 2);
++            c = apc_xchg(lock, 2);
++        }
++    }
++    
++}
++
++/* non-blocking lock returns 1 when the lock has been obtained, 0 if it would block */
++inline zend_bool apc_futex_nonblocking_lock(volatile int* lock)
++{
++    return apc_cmpxchg(lock, 0, 1) == 0;
++}
++
++
++inline void apc_futex_unlock(volatile int* lock)
++{
++    /* set the lock to 0, if it's previous values was not 1 (no waiters)
++     * then perform a wake operation on one process letting it know the lock 
++     * is available.  This is an optimization to save wake calls if there
++     * are no waiting processes for the lock 
++     */
++    if(apc_xchg(lock,0) != 1) {
++        apc_futex_wake(lock, 1);
++    }
++}
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_futex.h php-5.1.6/ext/APC/apc_futex.h
+--- php-5.1.6.old/ext/apc/apc_futex.h  1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_futex.h      2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,55 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Brian Shire <shire@php.net>                                 |
++  +----------------------------------------------------------------------+
++
++ */
++
++/* $Id: apc_futex.h,v 3.2 2006/10/12 08:23:16 shire Exp $ */
++
++#ifndef APC_FUTEX_H
++#define APC_FUTEX_H
++
++#include "apc.h"
++
++#ifdef APC_FUTEX_LOCKS 
++
++#include <asm/types.h>
++#include <unistd.h>
++#include <linux/futex.h>
++
++#include "arch/atomic.h"
++
++#define sys_futex(futex, op, val, timeout) syscall(SYS_futex, futex, op, val, timeout)
++#define apc_futex_wait(val, oldval) sys_futex((void*)val, FUTEX_WAIT, oldval, NULL)
++#define apc_futex_wake(val, count) sys_futex((void*)val, FUTEX_WAKE, count, NULL)
++
++int apc_futex_create();
++void apc_futex_destroy(volatile int* lock);
++void apc_futex_lock(volatile int* lock);
++void apc_futex_unlock(volatile int* lock);
++
++#endif
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_globals.h php-5.1.6/ext/APC/apc_globals.h
+--- php-5.1.6.old/ext/apc/apc_globals.h        1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_globals.h    2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,110 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt.                                 |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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.59 2007/03/21 21:07:28 rasmus Exp $ */
++
++#ifndef APC_GLOBALS_H
++#define APC_GLOBALS_H
++
++#define APC_VERSION "3.0.14"
++
++#include "apc_cache.h"
++#include "apc_stack.h"
++#include "apc_php.h"
++
++ZEND_BEGIN_MODULE_GLOBALS(apc)
++    /* configuration parameters */
++    zend_bool enabled;      /* if true, apc is enabled (defaults to true) */
++    long shm_segments;      /* number of shared memory segments to use */
++    long shm_size;          /* size of each shared memory segment (in MB) */
++    long num_files_hint;    /* parameter to apc_cache_create */
++    long user_entries_hint;
++    long gc_ttl;            /* parameter to apc_cache_create */
++    long ttl;               /* parameter to apc_cache_create */
++    long user_ttl;
++#if APC_MMAP
++    char *mmap_file_mask;   /* mktemp-style file-mask to pass to mmap */
++#endif
++    char** filters;         /* array of regex filters that prevent caching */
++
++    /* module variables */
++    zend_bool initialized;       /* true if module was initialized */
++    apc_stack_t* cache_stack;    /* the stack of cached executable code */
++    zend_bool cache_by_default;  /* true if files should be cached unless filtered out */
++                                 /* false if files should only be cached if filtered in */
++    long slam_defense;           /* Probability of a process not caching an uncached file */
++    size_t* mem_size_ptr;        /* size of blocks allocated to file being cached (NULL outside my_compile_file) */
++    long file_update_protection; /* Age in seconds before a file is eligible to be cached - 0 to disable */
++    zend_bool enable_cli;        /* Flag to override turning APC off for CLI */
++    long max_file_size;                /* Maximum size of file, in bytes that APC will be allowed to cache */
++    long slam_rand;              /* A place to store the slam rand value for the request */
++    zend_bool fpstat;            /* true if fullpath includes should be stat'ed */
++    zend_bool stat_ctime;        /* true if ctime in addition to mtime should be checked */
++    zend_bool write_lock;        /* true for a global write lock */
++    zend_bool report_autofilter; /* true for auto-filter warnings */
++    zend_bool include_once;        /* Override the ZEND_INCLUDE_OR_EVAL opcode handler to avoid pointless fopen()s [still experimental] */
++    apc_optimize_function_t apc_optimize_function;   /* optimizer function callback */
++#ifdef MULTIPART_EVENT_FORMDATA
++    zend_bool rfc1867;           /* Flag to enable rfc1867 handler */
++#endif
++    HashTable *copied_zvals;     /* my_copy recursion detection list */
++#ifdef ZEND_ENGINE_2
++    int reserved_offset;         /* offset for apc info in op_array->reserved[] */
++#endif
++    zend_bool localcache;        /* enable local cache */
++    long localcache_size;        /* size of fast cache */
++    apc_local_cache_t* lcache;   /* unlocked local cache */
++ZEND_END_MODULE_GLOBALS(apc)
++
++/* (the following declaration is defined in php_apc.c) */
++ZEND_EXTERN_MODULE_GLOBALS(apc)
++
++#ifdef ZTS
++# define APCG(v) TSRMG(apc_globals_id, zend_apc_globals *, v)
++#else
++# define APCG(v) (apc_globals.v)
++#endif
++
++/* True globals */
++extern apc_cache_t* apc_cache;       /* the global compiler cache */
++extern apc_cache_t* apc_user_cache;  /* the global user content cache */
++extern void* apc_compiled_filters;   /* compiled filters */
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc.h php-5.1.6/ext/APC/apc.h
+--- php-5.1.6.old/ext/apc/apc.h        1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc.h    2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,126 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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.h,v 3.14 2007/03/17 14:01:41 gopalv Exp $ */
++
++#ifndef APC_H
++#define APC_H
++
++/*
++ * This module defines utilities and helper functions used elsewhere in APC.
++ */
++
++/* Commonly needed C library headers. */
++#include <assert.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++
++/* UNIX headers (needed for struct stat) */
++#include <sys/types.h>
++#include <sys/stat.h>
++#ifndef PHP_WIN32
++#include <unistd.h>
++#endif
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include "php.h"
++
++/* log levels constants (see apc_log) */
++enum { APC_DBG, APC_NOTICE, APC_WARNING, APC_ERROR };
++
++/* typedefs for extensible memory allocators */
++typedef void* (*apc_malloc_t)(size_t);
++typedef void  (*apc_free_t)  (void*);
++
++/* wrappers for memory allocation routines */
++extern void* apc_emalloc(size_t n);
++extern void* apc_erealloc(void* p, size_t n);
++extern void apc_efree(void* p);
++extern char* apc_estrdup(const char* s);
++extern void* apc_xstrdup(const char* s, apc_malloc_t f);
++extern void* apc_xmemcpy(const void* p, size_t n, apc_malloc_t f);
++
++/* console display functions */
++extern void apc_log(int level, const char* fmt, ...);
++extern void apc_eprint(const char* fmt, ...);
++extern void apc_wprint(const char* fmt, ...);
++extern void apc_dprint(const char* fmt, ...);
++extern void apc_nprint(const char* fmt, ...);
++
++/* string and text manipulation */
++extern char* apc_append(const char* s, const char* t);
++extern char* apc_substr(const char* s, int start, int length);
++extern char** apc_tokenize(const char* s, char delim);
++
++/* filesystem functions */
++
++typedef struct apc_fileinfo_t 
++{
++    char fullpath[MAXPATHLEN+1];
++    struct stat st_buf;
++} apc_fileinfo_t;
++
++#ifndef PHP_WIN32
++#define apc_stat(f, b) stat(f, b)
++#else
++#define apc_stat(f, b) apc_win32_stat(f, b TSRMLS_CC)
++extern int apc_win32_stat(const char *path, struct stat *buf TSRMLS_DC);
++#endif
++extern int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo);
++
++/* regular expression wrapper functions */
++extern void* apc_regex_compile_array(char* patterns[]);
++extern void apc_regex_destroy_array(void* p);
++extern int apc_regex_match_array(void* p, const char* input);
++
++/* apc_crc32: returns the CRC-32 checksum of the first len bytes in buf */
++extern unsigned int apc_crc32(const char* buf, int len);
++
++#define APC_NEGATIVE_MATCH 1
++#define APC_POSITIVE_MATCH 2
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_lock.h php-5.1.6/ext/APC/apc_lock.h
+--- php-5.1.6.old/ext/apc/apc_lock.h   1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_lock.h       2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,105 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: George Schlossnagle <george@omniti.com>                     |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  +----------------------------------------------------------------------+
++
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
++
++   All other licensing and usage conditions are those of the PHP Group.
++
++ */
++
++/* $Id: apc_lock.h,v 3.20 2007/01/29 07:39:02 shire Exp $ */
++
++#ifndef APC_LOCK
++#define APC_LOCK
++
++#include "apc_sem.h"
++#include "apc_fcntl.h"
++#include "apc_pthreadmutex.h"
++#include "apc_futex.h"
++#include "apc_spin.h"
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#ifdef TSRM_LOCKS
++#define RDLOCK_AVAILABLE 0
++#define NONBLOCKING_LOCK_AVAILABLE 0
++/* quick & dirty: use TSRM mutex locks for now */
++#define apc_lck_create(a,b,c,d) d=(int)tsrm_mutex_alloc()
++#define apc_lck_destroy(a)    tsrm_mutex_free((MUTEX_T)a)
++#define apc_lck_lock(a)       tsrm_mutex_lock((MUTEX_T)a)
++#define apc_lck_rdlock(a)     tsrm_mutex_lock((MUTEX_T)a)
++#define apc_lck_unlock(a)     tsrm_mutex_unlock((MUTEX_T)a)
++#elif defined(APC_SEM_LOCKS)
++#define RDLOCK_AVAILABLE 0
++#define NONBLOCKING_LOCK_AVAILABLE 0
++#define apc_lck_t int
++#define apc_lck_create(a,b,c,d) d=apc_sem_create(NULL,(b),(c))
++#define apc_lck_destroy(a)    apc_sem_destroy(a)
++#define apc_lck_lock(a)       apc_sem_lock(a)
++#define apc_lck_rdlock(a)     apc_sem_lock(a)
++#define apc_lck_unlock(a)     apc_sem_unlock(a)
++#elif defined(APC_PTHREADMUTEX_LOCKS)
++#define RDLOCK_AVAILABLE 0
++#define NONBLOCKING_LOCK_AVAILABLE 1
++#define apc_lck_t pthread_mutex_t 
++#define apc_lck_create(a,b,c,d) apc_pthreadmutex_create((pthread_mutex_t*)&d)
++#define apc_lck_destroy(a)    apc_pthreadmutex_destroy(&a)
++#define apc_lck_lock(a)       apc_pthreadmutex_lock(&a)
++#define apc_lck_nb_lock(a)    apc_pthreadmutex_nonblocking_lock(&a)
++#define apc_lck_rdlock(a)     apc_pthreadmutex_lock(&a)
++#define apc_lck_unlock(a)     apc_pthreadmutex_unlock(&a)
++#elif defined(APC_FUTEX_LOCKS)
++#define NONBLOCKING_LOCK_AVAILABLE 1 
++#define apc_lck_t int 
++#define apc_lck_create(a,b,c,d) d=apc_futex_create()
++#define apc_lck_destroy(a)    apc_futex_destroy(&a)
++#define apc_lck_lock(a)       apc_futex_lock(&a)
++#define apc_lck_nb_lock(a)    apc_futex_nonblocking_lock(&a)
++#define apc_lck_rdlock(a)     apc_futex_lock(&a)
++#define apc_lck_unlock(a)     apc_futex_unlock(&a)
++#elif defined(APC_SPIN_LOCKS)
++#define NONBLOCKING_LOCK_AVAILABLE APC_SLOCK_NONBLOCKING_LOCK_AVAILABLE
++#define apc_lck_t slock_t 
++#define apc_lck_create(a,b,c,d) apc_slock_create((slock_t*)&(d))
++#define apc_lck_destroy(a)    apc_slock_destroy(&a)
++#define apc_lck_lock(a)       apc_slock_lock(&a)
++#define apc_lck_nb_lock(a)    apc_slock_nonblocking_lock(&a)
++#define apc_lck_rdlock(a)     apc_slock_lock(&a)
++#define apc_lck_unlock(a)     apc_slock_unlock(&a)
++#else
++#define RDLOCK_AVAILABLE 1
++#ifdef PHP_WIN32
++#define NONBLOCKING_LOCK_AVAILABLE 0
++#else
++#define NONBLOCKING_LOCK_AVAILABLE 1
++#endif
++#define apc_lck_t int
++#define apc_lck_create(a,b,c,d) d=apc_fcntl_create((a))
++#define apc_lck_destroy(a)    apc_fcntl_destroy(a)
++#define apc_lck_lock(a)       apc_fcntl_lock(a)
++#define apc_lck_nb_lock(a)    apc_fcntl_nonblocking_lock(a)
++#define apc_lck_rdlock(a)     apc_fcntl_rdlock(a)
++#define apc_lck_unlock(a)     apc_fcntl_unlock(a)
++#endif
++
++#endif
+diff -ruN php-5.1.6.old/ext/apc/apc_main.c php-5.1.6/ext/APC/apc_main.c
+--- php-5.1.6.old/ext/apc/apc_main.c   1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_main.c       2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,681 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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.97 2007/03/22 16:03:59 gopalv Exp $ */
++
++#include "apc_php.h"
++#include "apc_main.h"
++#include "apc.h"
++#include "apc_lock.h"
++#include "apc_cache.h"
++#include "apc_compile.h"
++#include "apc_globals.h"
++#include "apc_sma.h"
++#include "apc_stack.h"
++#include "apc_zend.h"
++#include "SAPI.h"
++#if PHP_API_VERSION <= 20020918
++#if HAVE_APACHE
++#ifdef APC_PHP4_STAT
++#undef XtOffsetOf
++#include "httpd.h"
++#endif
++#endif
++#endif
++
++/* {{{ module variables */
++
++/* pointer to the original Zend engine compile_file function */
++typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
++static zend_compile_t *old_compile_file;
++
++/* }}} */
++
++/* {{{ get/set old_compile_file (to interact with other extensions that need the compile hook) */
++static zend_compile_t* set_compile_hook(zend_compile_t *ptr)
++{
++    zend_compile_t *retval = old_compile_file;
++
++    if (ptr != NULL) old_compile_file = ptr;
++    return retval;
++}
++/* }}} */
++
++/* {{{ install_function */
++static int install_function(apc_function_t fn TSRMLS_DC)
++{
++    int status =
++        zend_hash_add(EG(function_table),
++                      fn.name,
++                      fn.name_len+1,
++                      apc_copy_function_for_execution(fn.function),
++                      sizeof(fn.function[0]),
++                      NULL);
++
++    if (status == FAILURE) {
++        /* apc_eprint("Cannot redeclare %s()", fn.name); */
++    }
++
++    return status;
++}
++/* }}} */
++
++/* {{{ install_class */
++static int install_class(apc_class_t cl TSRMLS_DC)
++{
++    zend_class_entry* class_entry = cl.class_entry;
++    zend_class_entry* parent = NULL;
++    int status;
++#ifdef ZEND_ENGINE_2
++    zend_class_entry** allocated_ce = NULL;
++#endif
++
++
++    /* Special case for mangled names. Mangled names are unique to a file.
++     * There is no way two classes with the same mangled name will occur,
++     * unless a file is included twice. And if in case, a file is included
++     * twice, all mangled name conflicts can be ignored and the class redeclaration
++     * error may be deferred till runtime of the corresponding DECLARE_CLASS
++     * calls.
++     */
++
++    if(cl.name_len != 0 && cl.name[0] == '\0') {
++        if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) {
++            return SUCCESS;
++        }
++    }
++    
++#ifdef ZEND_ENGINE_2    
++    /*
++     * XXX: We need to free this somewhere...
++     */
++    allocated_ce = apc_php_malloc(sizeof(zend_class_entry*));    
++
++    if(!allocated_ce) {
++        return FAILURE;
++    }
++
++    *allocated_ce = 
++#endif        
++    class_entry =
++        apc_copy_class_entry_for_execution(cl.class_entry,
++                                           cl.is_derived);
++
++
++    /* restore parent class pointer for compile-time inheritance */
++    if (cl.parent_name != NULL) {
++#ifdef ZEND_ENGINE_2    
++        zend_class_entry** parent_ptr = NULL;
++        /*
++         * zend_lookup_class has to be due to presence of __autoload, 
++         * just looking up the EG(class_table) is not enough in php5!
++         * Even more dangerously, thanks to __autoload and people using
++         * class names as filepaths for inclusion, this has to be case
++         * sensitive. zend_lookup_class automatically does a case_fold
++         * internally, but passes the case preserved version to __autoload.
++         * Aside: Do NOT pass *strlen(cl.parent_name)+1* because 
++         * zend_lookup_class does it internally anyway!
++         */
++        status = zend_lookup_class(cl.parent_name,
++                                    strlen(cl.parent_name),
++                                    &parent_ptr TSRMLS_CC);
++#else
++        status = zend_hash_find(EG(class_table),
++                                cl.parent_name,
++                                strlen(cl.parent_name)+1,
++                                (void**) &parent);
++#endif
++        if (status == FAILURE) {
++            if(APCG(report_autofilter)) {
++                apc_wprint("Dynamic inheritance detected for class %s", cl.name);
++            }
++            class_entry->parent = NULL;
++            return status;
++        }
++        else {
++#ifdef ZEND_ENGINE_2            
++            parent = *parent_ptr;
++#endif 
++            class_entry->parent = parent;
++#ifdef ZEND_ENGINE_2
++            zend_do_inheritance(class_entry, parent TSRMLS_CC);
++#else
++            zend_do_inheritance(class_entry, parent);
++#endif
++        }
++
++
++    }
++
++#ifdef ZEND_ENGINE_2                           
++    status = zend_hash_add(EG(class_table),
++                           cl.name,
++                           cl.name_len+1,
++                           allocated_ce,
++                           sizeof(zend_class_entry*),
++                           NULL);
++#else                           
++    status = zend_hash_add(EG(class_table),
++                           cl.name,
++                           cl.name_len+1,
++                           class_entry,
++                           sizeof(zend_class_entry),
++                           NULL);
++#endif                           
++
++    if (status == FAILURE) {
++        apc_eprint("Cannot redeclare class %s", cl.name);
++    } 
++    return status;
++}
++/* }}} */
++
++/* {{{ uninstall_class */
++static int uninstall_class(apc_class_t cl TSRMLS_DC)
++{
++    int status;
++
++#ifdef ZEND_ENGINE_2                           
++    status = zend_hash_del(EG(class_table),
++                           cl.name,
++                           cl.name_len+1);
++#else                           
++    status = zend_hash_del(EG(class_table),
++                           cl.name,
++                           cl.name_len+1);
++#endif                           
++    if (status == FAILURE) {
++        apc_eprint("Cannot delete class %s", cl.name);
++    } 
++    return status;
++}
++/* }}} */
++
++/* {{{ compare_file_handles */
++static int compare_file_handles(void* a, void* b)
++{
++    zend_file_handle* fh1 = (zend_file_handle*)a;
++    zend_file_handle* fh2 = (zend_file_handle*)b;
++    return (fh1->type == fh2->type && 
++            fh1->filename == fh2->filename &&
++            fh1->opened_path == fh2->opened_path);
++}
++/* }}} */
++
++/* {{{ cached_compile */
++static zend_op_array* cached_compile(zend_file_handle* h,
++                                        int type TSRMLS_DC)
++{
++    apc_cache_entry_t* cache_entry;
++    int i, ii;
++
++    cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack));
++    assert(cache_entry != NULL);
++
++    if (cache_entry->data.file.classes) {
++        for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
++            if(install_class(cache_entry->data.file.classes[i] TSRMLS_CC) == FAILURE) {
++                goto default_compile;
++            }
++        }
++    }
++
++    if (cache_entry->data.file.functions) {
++        for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
++            install_function(cache_entry->data.file.functions[i] TSRMLS_CC);
++        }
++    }
++
++
++    return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array TSRMLS_CC);
++
++default_compile:
++
++    cache_entry->autofiltered = 1;
++    if(APCG(report_autofilter)) {
++        apc_wprint("Autofiltering %s", h->opened_path);
++    }
++
++    if(cache_entry->data.file.classes) {
++        for(ii = 0; ii < i ; ii++) {
++            uninstall_class(cache_entry->data.file.classes[ii] TSRMLS_CC);
++        }
++    }
++    
++    apc_stack_pop(APCG(cache_stack)); /* pop out cache_entry */
++
++    /* cannot free up cache data yet, it maybe in use */
++    
++    zend_llist_del_element(&CG(open_files), h, compare_file_handles); /* XXX: kludge */
++    
++    h->type = ZEND_HANDLE_FILENAME;
++    
++    return old_compile_file(h, type TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ my_compile_file
++   Overrides zend_compile_file */
++static zend_op_array* my_compile_file(zend_file_handle* h,
++                                               int type TSRMLS_DC)
++{
++    apc_cache_key_t key;
++    apc_cache_entry_t* cache_entry;
++    zend_op_array* op_array;
++    int num_functions, num_classes, ret;
++    zend_op_array* alloc_op_array;
++    apc_function_t* alloc_functions;
++    apc_class_t* alloc_classes;
++    time_t t;
++    char *path;
++    size_t mem_size;
++
++    if (!APCG(enabled) || (apc_cache_busy(apc_cache) && !APCG(localcache))) {
++              return old_compile_file(h, type TSRMLS_CC);
++      }
++
++    /* check our regular expression filters */
++    if (APCG(filters) && apc_compiled_filters) {
++        int ret = apc_regex_match_array(apc_compiled_filters, h->filename);
++        if(ret == APC_NEGATIVE_MATCH || (ret != APC_POSITIVE_MATCH && !APCG(cache_by_default))) {
++            return old_compile_file(h, type TSRMLS_CC);
++        }
++    } else if(!APCG(cache_by_default)) {
++        return old_compile_file(h, type TSRMLS_CC);
++    }
++
++#if PHP_API_VERSION <= 20041225
++#if HAVE_APACHE && defined(APC_PHP4_STAT)
++    t = ((request_rec *)SG(server_context))->request_time;
++#else 
++    t = time(0);
++#endif
++#else 
++    t = sapi_get_request_time(TSRMLS_C);
++#endif
++
++#ifdef __DEBUG_APC__
++    fprintf(stderr,"1. h->opened_path=[%s]  h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename);
++#endif
++
++    /* try to create a cache key; if we fail, give up on caching */
++    if (!apc_cache_make_file_key(&key, h->filename, PG(include_path), t TSRMLS_CC)) {
++        return old_compile_file(h, type TSRMLS_CC);
++    }
++
++    if(APCG(localcache)) {
++        /* search for the file in the local cache */
++        cache_entry = apc_local_cache_find(APCG(lcache), key, t);
++    } else {
++        /* search for the file in the cache */
++        cache_entry = apc_cache_find(apc_cache, key, t);
++    }
++
++    if (cache_entry != NULL && !cache_entry->autofiltered) {
++        int dummy = 1;
++        if (h->opened_path == NULL) {
++            h->opened_path = estrdup(cache_entry->data.file.filename);
++        }
++        zend_hash_add(&EG(included_files), h->opened_path, strlen(h->opened_path)+1, (void *)&dummy, sizeof(int), NULL);
++        zend_llist_add_element(&CG(open_files), h); /* XXX kludge */
++        apc_stack_push(APCG(cache_stack), cache_entry);
++        return cached_compile(h, type TSRMLS_CC);
++    }
++    else if(cache_entry != NULL && cache_entry->autofiltered) {
++        /* nobody else is using this cache_entry */ 
++        if(cache_entry->ref_count == 1) {
++            if(cache_entry->data.file.op_array) {
++                apc_free_op_array(cache_entry->data.file.op_array, apc_sma_free);
++                cache_entry->data.file.op_array = NULL;
++            }
++            if(cache_entry->data.file.functions) {
++                apc_free_functions(cache_entry->data.file.functions, apc_sma_free);
++                cache_entry->data.file.functions = NULL;
++            }
++            if(cache_entry->data.file.classes) {
++                apc_free_classes(cache_entry->data.file.classes, apc_sma_free);
++                cache_entry->data.file.classes = NULL;        
++            }
++        }
++        /* We never push this into the cache_stack, so we have to do a release */
++        apc_cache_release(apc_cache, cache_entry);
++        return old_compile_file(h, type TSRMLS_CC);
++    }
++    
++    if(apc_cache_busy(apc_cache) && APCG(localcache)) {
++        /* possibly local cache returned NULL because cache is busy */
++              return old_compile_file(h, type TSRMLS_CC);
++      }
++
++    /* remember how many functions and classes existed before compilation */
++    num_functions = zend_hash_num_elements(CG(function_table));
++    num_classes   = zend_hash_num_elements(CG(class_table));
++    
++    /* compile the file using the default compile function */
++    op_array = old_compile_file(h, type TSRMLS_CC);
++    if (op_array == NULL) {
++        return NULL;
++    }
++    /*
++     * Basically this will cause a file only to be cached on a percentage 
++     * of the attempts.  This is to avoid cache slams when starting up a
++     * very busy server or when modifying files on a very busy live server.
++     * There is no point having many processes all trying to cache the same
++     * file at the same time.  By introducing a chance of being cached
++     * we theoretically cut the cache slam problem by the given percentage.
++     * For example if apc.slam_defense is set to 66 then 2/3 of the attempts
++     * to cache an uncached file will be ignored.
++     */
++    if(APCG(slam_defense)) {
++        if(APCG(slam_rand)==-1) {
++            APCG(slam_rand) = (int)(100.0*rand()/(RAND_MAX+1.0));
++        }
++        if(APCG(slam_rand) < APCG(slam_defense)) {
++            return op_array;
++        }
++    }
++
++    HANDLE_BLOCK_INTERRUPTIONS();
++
++#if NONBLOCKING_LOCK_AVAILABLE
++    if(APCG(write_lock)) {
++        if(!apc_cache_write_lock(apc_cache)) {
++            HANDLE_UNBLOCK_INTERRUPTIONS();
++            return op_array;
++        }
++    }
++#endif
++
++    mem_size = 0;
++    APCG(mem_size_ptr) = &mem_size;
++    if(!(alloc_op_array = apc_copy_op_array(NULL, op_array, apc_sma_malloc, apc_sma_free TSRMLS_CC))) {
++        apc_cache_expunge(apc_cache,t);
++        apc_cache_expunge(apc_user_cache,t);
++        APCG(mem_size_ptr) = NULL;
++#if NONBLOCKING_LOCK_AVAILABLE
++        if(APCG(write_lock)) {
++            apc_cache_write_unlock(apc_cache);
++        }
++#endif
++        HANDLE_UNBLOCK_INTERRUPTIONS();
++        return op_array;
++    }
++    
++    if(!(alloc_functions = apc_copy_new_functions(num_functions, apc_sma_malloc, apc_sma_free TSRMLS_CC))) {
++        apc_free_op_array(alloc_op_array, apc_sma_free);
++        apc_cache_expunge(apc_cache,t);
++        apc_cache_expunge(apc_user_cache,t);
++        APCG(mem_size_ptr) = NULL;
++#if NONBLOCKING_LOCK_AVAILABLE
++        if(APCG(write_lock)) {
++            apc_cache_write_unlock(apc_cache);
++        }
++#endif
++        HANDLE_UNBLOCK_INTERRUPTIONS();
++        return op_array;
++    }
++    if(!(alloc_classes = apc_copy_new_classes(op_array, num_classes, apc_sma_malloc, apc_sma_free TSRMLS_CC))) {
++        apc_free_op_array(alloc_op_array, apc_sma_free);
++        apc_free_functions(alloc_functions, apc_sma_free);
++        apc_cache_expunge(apc_cache,t);
++        apc_cache_expunge(apc_user_cache,t);
++        APCG(mem_size_ptr) = NULL;
++#if NONBLOCKING_LOCK_AVAILABLE
++        if(APCG(write_lock)) {
++            apc_cache_write_unlock(apc_cache);
++        }
++#endif
++        HANDLE_UNBLOCK_INTERRUPTIONS();
++        return op_array;
++    }
++
++    path = h->opened_path;
++    if(!path) path=h->filename;
++
++#ifdef __DEBUG_APC__
++    fprintf(stderr,"2. h->opened_path=[%s]  h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename);
++#endif
++
++    if(!(cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes))) {
++        apc_free_op_array(alloc_op_array, apc_sma_free);
++        apc_free_functions(alloc_functions, apc_sma_free);
++        apc_free_classes(alloc_classes, apc_sma_free);
++        apc_cache_expunge(apc_cache,t);
++        apc_cache_expunge(apc_user_cache,t);
++        APCG(mem_size_ptr) = NULL;
++#if NONBLOCKING_LOCK_AVAILABLE
++        if(APCG(write_lock)) {
++            apc_cache_write_unlock(apc_cache);
++        }
++#endif
++        HANDLE_UNBLOCK_INTERRUPTIONS();
++        return op_array;
++    }
++    APCG(mem_size_ptr) = NULL;
++    cache_entry->mem_size = mem_size;
++
++    if ((ret = apc_cache_insert(apc_cache, key, cache_entry, t)) != 1) {
++        apc_cache_free_entry(cache_entry);
++        if(ret==-1) {
++            apc_cache_expunge(apc_cache,t);
++            apc_cache_expunge(apc_user_cache,t);
++        }
++    }
++
++#if NONBLOCKING_LOCK_AVAILABLE
++    if(APCG(write_lock)) {
++        apc_cache_write_unlock(apc_cache);
++    }
++#endif
++    HANDLE_UNBLOCK_INTERRUPTIONS();
++
++    return op_array;
++}
++/* }}} */
++
++/* {{{ module init and shutdown */
++
++int apc_module_init(int module_number TSRMLS_DC)
++{
++    /* apc initialization */
++#if APC_MMAP
++    apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, APCG(mmap_file_mask));
++#else
++    apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, NULL);
++#endif
++    apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl));
++    apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl));
++
++    apc_compiled_filters = apc_regex_compile_array(APCG(filters));
++
++    /* override compilation */
++    old_compile_file = zend_compile_file;
++    zend_compile_file = my_compile_file;
++    REGISTER_LONG_CONSTANT("\000apc_magic", (long)&set_compile_hook, CONST_PERSISTENT | CONST_CS);
++
++    APCG(initialized) = 1;
++    return 0;
++}
++
++int apc_module_shutdown(TSRMLS_D)
++{
++    if (!APCG(initialized))
++        return 0;
++
++    /* restore compilation */
++    zend_compile_file = old_compile_file;
++
++    /* 
++     * In case we got interrupted by a SIGTERM or something else during execution
++     * we may have cache entries left on the stack that we need to check to make
++     * sure that any functions or classes these may have added to the global function
++     * and class tables are removed before we blow away the memory that hold them.
++     * 
++     * This is merely to remove memory leak warnings - as the process is terminated
++     * immediately after shutdown. The following while loop can be removed without
++     * affecting anything else.
++     */
++    while (apc_stack_size(APCG(cache_stack)) > 0) {
++        int i;
++        apc_cache_entry_t* cache_entry = (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
++        if (cache_entry->data.file.functions) {
++            for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
++                zend_hash_del(EG(function_table),
++                    cache_entry->data.file.functions[i].name,
++                    cache_entry->data.file.functions[i].name_len+1);
++            }
++        }
++        if (cache_entry->data.file.classes) {
++            for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
++                zend_hash_del(EG(class_table),
++                    cache_entry->data.file.classes[i].name,
++                    cache_entry->data.file.classes[i].name_len+1);
++            }
++        }
++        apc_cache_release(apc_cache, cache_entry);
++    }
++
++    apc_cache_destroy(apc_cache);
++    apc_cache_destroy(apc_user_cache);
++    apc_sma_cleanup();
++
++    APCG(initialized) = 0;
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ process init and shutdown */
++int apc_process_init(int module_number TSRMLS_DC)
++{
++    int minttl = (APCG(gc_ttl) >  APCG(ttl) ? APCG(ttl) : APCG(gc_ttl))/2;
++    int size = APCG(localcache_size);
++    if(APCG(initialized) && APCG(localcache)) {
++        /* TTL is 2 mins by default */
++        APCG(lcache) = apc_local_cache_create(apc_cache, size, minttl ? minttl : 120); 
++    }
++    return 0;
++}
++
++int apc_process_shutdown(TSRMLS_D)
++{
++    if(APCG(initialized) && APCG(localcache) && APCG(lcache)) {
++        apc_local_cache_destroy(APCG(lcache));
++        APCG(lcache) = NULL;
++    }
++      return 0;
++}
++/* }}} */
++
++/* {{{ request init and shutdown */
++
++int apc_request_init(TSRMLS_D)
++{
++    apc_stack_clear(APCG(cache_stack));
++    APCG(slam_rand) = -1;
++    APCG(copied_zvals) = NULL;
++    return 0;
++}
++
++int apc_request_shutdown(TSRMLS_D)
++{
++    apc_deactivate(TSRMLS_C);
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ apc_deactivate */
++void apc_deactivate(TSRMLS_D)
++{
++    /* The execution stack was unwound, which prevented us from decrementing
++     * the reference counts on active cache entries in `my_execute`.
++     */
++    while (apc_stack_size(APCG(cache_stack)) > 0) {
++        int i;
++        zend_class_entry* zce = NULL;
++        void ** centry = (void*)(&zce);
++#ifdef ZEND_ENGINE_2
++        zend_class_entry** pzce = NULL;
++#endif
++        
++        apc_cache_entry_t* cache_entry =
++            (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
++
++        if (cache_entry->data.file.functions) {
++            for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
++                zend_hash_del(EG(function_table),
++                    cache_entry->data.file.functions[i].name,
++                    cache_entry->data.file.functions[i].name_len+1);
++            }
++        }
++
++        if (cache_entry->data.file.classes) {
++            for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
++#ifdef ZEND_ENGINE_2
++                centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */
++#endif
++                if(zend_hash_find(EG(class_table), 
++                    cache_entry->data.file.classes[i].name,
++                    cache_entry->data.file.classes[i].name_len+1,
++                    (void**)centry) == FAILURE)
++                {
++                    /* double inclusion of conditional classes ends up failing 
++                     * this lookup the second time around.
++                     */
++                    continue;
++                }
++
++#ifdef ZEND_ENGINE_2
++                zce = *pzce;
++#endif
++                zend_hash_del(EG(class_table),
++                    cache_entry->data.file.classes[i].name,
++                    cache_entry->data.file.classes[i].name_len+1);
++                
++                apc_free_class_entry_after_execution(zce);
++            }
++        }
++        apc_cache_release(apc_cache, cache_entry);
++    }
++    if(APCG(localcache)) {
++        apc_local_cache_cleanup(APCG(lcache)); 
++    }
++}
++/* }}} */
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_main.h php-5.1.6/ext/APC/apc_main.h
+--- php-5.1.6.old/ext/apc/apc_main.h   1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_main.h       2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,67 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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_main.h,v 3.9 2007/02/28 01:15:18 gopalv Exp $ */
++
++#ifndef APC_MAIN_H
++#define APC_MAIN_H
++
++/*
++ * This module provides the primary interface between PHP and APC.
++ */
++
++extern int apc_module_init(int module_number TSRMLS_DC);
++extern int apc_module_shutdown(TSRMLS_D);
++extern int apc_process_init(int module_number TSRMLS_DC);
++extern int apc_process_shutdown(TSRMLS_D);
++extern int apc_request_init(TSRMLS_D);
++extern int apc_request_shutdown(TSRMLS_D);
++
++/*
++ * apc_deactivate is called by the PHP interpreter when an "exception" is
++ * raised (e.g., a call to the exit function) that unwinds the execution
++ * stack.
++ */
++extern void apc_deactivate();
++
++
++extern const char* apc_version();
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_mmap.c php-5.1.6/ext/APC/apc_mmap.c
+--- php-5.1.6.old/ext/apc/apc_mmap.c   1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_mmap.c       2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,137 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Rasmus Lerdorf <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.5 2006/03/12 00:31:45 rasmus 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, int size)
++{
++    void* shmaddr;  /* the shared memory address */
++
++    /* If no filename was provided, do an anonymous mmap */
++    if(!file_mask || (file_mask && !strlen(file_mask))) {
++        shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
++    } else {
++        int fd;
++
++        /* 
++         * If the filemask contains .shm we try to do a POSIX-compliant shared memory
++         * backed mmap which should avoid synchs on some platforms.  At least on
++         * FreeBSD this implies MAP_NOSYNC and on Linux it is equivalent of mmap'ing
++         * a file in a mounted shmfs.  For this to work on Linux you need to make sure
++         * you actually have shmfs mounted.  Also on Linux, make sure the file_mask you
++         * pass in has a leading / and no other /'s.  eg.  /apc.shm.XXXXXX
++         * On FreeBSD these are mapped onto the regular filesystem so you can put whatever
++         * path you want here.
++         */
++        if(strstr(file_mask,".shm")) {
++            mktemp(file_mask);
++            fd = shm_open(file_mask, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
++            if(fd == -1) {
++                apc_eprint("apc_mmap: shm_open on %s failed:", file_mask);
++                return (void *)-1;
++            }
++            if (ftruncate(fd, size) < 0) {
++                close(fd);
++                shm_unlink(file_mask);
++                apc_eprint("apc_mmap: ftruncate failed:");
++                return (void *)-1;
++            }
++            shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
++            shm_unlink(file_mask);
++            close(fd);
++        }
++        /*
++         * Support anonymous mmap through the /dev/zero interface as well
++         */
++        else if(!strcmp(file_mask,"/dev/zero")) {
++            fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
++            if(fd == -1) {
++                apc_eprint("apc_mmap: open on /dev/zero failed:");
++                return (void *)-1;
++            }
++            shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
++            close(fd);
++        }
++        /* 
++         * Otherwise we do a normal filesystem mmap
++         */
++        else {
++            fd = mkstemp(file_mask);
++            if(fd == -1) {
++                apc_eprint("apc_mmap: mkstemp on %s failed:", file_mask);
++                return (void *)-1;
++            }
++            if (ftruncate(fd, size) < 0) {
++                close(fd);
++                unlink(file_mask);
++                apc_eprint("apc_mmap: ftruncate failed:");
++            }
++            shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOSYNC, fd, 0);
++            close(fd);
++            unlink(file_mask);
++        }
++    }
++    if((int)shmaddr == -1) {
++        apc_eprint("apc_mmap: mmap failed:");
++    }
++    return shmaddr;
++}
++
++void apc_unmap(void* shmaddr, int size)
++{
++    munmap(shmaddr, size);
++}
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc.php php-5.1.6/ext/APC/apc.php
+--- php-5.1.6.old/ext/apc/apc.php      1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc.php  2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,1313 @@
++<?php
++/*
++  +----------------------------------------------------------------------+
++  | 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: Ralf Becker <beckerr@php.net>                               |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  |          Ilia Alshanetsky <ilia@prohost.org>                         |
++  +----------------------------------------------------------------------+
++
++   All other licensing and usage conditions are those of the PHP Group.
++
++ */
++
++$VERSION='$Id: apc.php,v 3.65 2006/10/27 18:32:52 shire Exp $';
++
++////////// READ OPTIONAL CONFIGURATION FILE ////////////
++if (file_exists("apc.conf.php")) include("apc.conf.php");
++////////////////////////////////////////////////////////
++
++////////// BEGIN OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////
++
++defaults('USE_AUTHENTICATION',1);                     // Use (internal) authentication - best choice if 
++                                                                                      // no other authentication is available
++                                                                                      // If set to 0:
++                                                                                      //  There will be no further authentication. You 
++                                                                                      //  will have to handle this by yourself!
++                                                                                      // If set to 1:
++                                                                                      //  You need to change ADMIN_PASSWORD to make
++                                                                                      //  this work!
++defaults('ADMIN_USERNAME','apc');                     // Admin Username
++defaults('ADMIN_PASSWORD','password');        // Admin Password - CHANGE THIS TO ENABLE!!!
++
++// (beckerr) I'm using a clear text password here, because I've no good idea how to let 
++//           users generate a md5 or crypt password in a easy way to fill it in above
++
++//defaults('DATE_FORMAT', "d.m.Y H:i:s");     // German
++defaults('DATE_FORMAT', 'Y/m/d H:i:s');       // US
++
++defaults('GRAPH_SIZE',200);                                   // Image size
++
++////////// END OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////////
++
++
++// "define if not defined"
++function defaults($d,$v) {
++      if (!defined($d)) define($d,$v); // or just @define(...)
++}
++
++// rewrite $PHP_SELF to block XSS attacks
++//
++$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : '';
++$time = time();
++$host = getenv('HOSTNAME');
++if($host) { $host = '('.$host.')'; }
++
++// operation constants
++define('OB_HOST_STATS',1);
++define('OB_SYS_CACHE',2);
++define('OB_USER_CACHE',3);
++define('OB_SYS_CACHE_DIR',4);
++define('OB_VERSION_CHECK',9);
++
++// check validity of input variables
++$vardom=array(
++      'OB'    => '/^\d+$/',                   // operational mode switch
++      'CC'    => '/^[01]$/',                  // clear cache requested
++      'SH'    => '/^[a-z0-9]+$/',             // shared object description
++
++      'IMG'   => '/^[123]$/',                 // image to generate
++      'LO'    => '/^1$/',                             // login requested
++
++      'COUNT' => '/^\d+$/',                   // number of line displayed in list
++      'SCOPE' => '/^[AD]$/',                  // list view scope
++      'SORT1' => '/^[AHSMCDTZ]$/',    // first sort key
++      'SORT2' => '/^[DA]$/',                  // second sort key
++      'AGGR'  => '/^\d+$/',                   // aggregation by dir level
++      'SEARCH'        => '/^.*$/'                     // aggregation by dir level
++);
++
++// default cache mode
++$cache_mode='opcode';
++
++// cache scope
++$scope_list=array(
++      'A' => 'cache_list',
++      'D' => 'deleted_list'
++);
++
++// handle POST and GET requests
++if (empty($_REQUEST)) {
++      if (!empty($_GET) && !empty($_POST)) {
++              $_REQUEST = array_merge($_GET, $_POST);
++      } else if (!empty($_GET)) {
++              $_REQUEST = $_GET;
++      } else if (!empty($_POST)) {
++              $_REQUEST = $_POST;
++      } else {
++              $_REQUEST = array();
++      }
++}
++
++// check parameter syntax
++foreach($vardom as $var => $dom) {
++      if (!isset($_REQUEST[$var])) {
++              $MYREQUEST[$var]=NULL;
++      } else if (!is_array($_REQUEST[$var]) && preg_match($dom,$_REQUEST[$var])) {
++              $MYREQUEST[$var]=$_REQUEST[$var];
++      } else {
++              $MYREQUEST[$var]=$_REQUEST[$var]=NULL;
++      }
++}
++
++// check parameter sematics
++if (empty($MYREQUEST['SCOPE'])) $MYREQUEST['SCOPE']="A";
++if (empty($MYREQUEST['SORT1'])) $MYREQUEST['SORT1']="H";
++if (empty($MYREQUEST['SORT2'])) $MYREQUEST['SORT2']="D";
++if (empty($MYREQUEST['OB']))  $MYREQUEST['OB']=OB_HOST_STATS;
++if (!isset($MYREQUEST['COUNT'])) $MYREQUEST['COUNT']=20;
++if (!isset($scope_list[$MYREQUEST['SCOPE']])) $MYREQUEST['SCOPE']='A';
++
++$MY_SELF=
++      "$PHP_SELF".
++      "?SCOPE=".$MYREQUEST['SCOPE'].
++      "&SORT1=".$MYREQUEST['SORT1'].
++      "&SORT2=".$MYREQUEST['SORT2'].
++      "&COUNT=".$MYREQUEST['COUNT'];
++$MY_SELF_WO_SORT=
++      "$PHP_SELF".
++      "?SCOPE=".$MYREQUEST['SCOPE'].
++      "&COUNT=".$MYREQUEST['COUNT'];
++
++// authentication needed?
++//
++if (!USE_AUTHENTICATION) {
++      $AUTHENTICATED=1;
++} else {
++      $AUTHENTICATED=0;
++      if (ADMIN_PASSWORD!='password' && ($MYREQUEST['LO'] == 1 || isset($_SERVER['PHP_AUTH_USER']))) {
++
++              if (!isset($_SERVER['PHP_AUTH_USER']) ||
++                      !isset($_SERVER['PHP_AUTH_PW']) ||
++                      $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||
++                      $_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) {
++                      Header("WWW-Authenticate: Basic realm=\"APC Login\"");
++                      Header("HTTP/1.0 401 Unauthorized");
++
++                      echo <<<EOB
++                              <html><body>
++                              <h1>Rejected!</h1>
++                              <big>Wrong Username or Password!</big><br/>&nbsp;<br/>&nbsp;
++                              <big><a href='$PHP_SELF?OB={$MYREQUEST['OB']}'>Continue...</a></big>
++                              </body></html>
++EOB;
++                      exit;
++                      
++              } else {
++                      $AUTHENTICATED=1;
++              }
++      }
++}
++      
++// select cache mode
++if ($AUTHENTICATED && $MYREQUEST['OB'] == OB_USER_CACHE) {
++      $cache_mode='user';
++}
++// clear cache
++if ($AUTHENTICATED && isset($MYREQUEST['CC']) && $MYREQUEST['CC']) {
++      apc_clear_cache($cache_mode);
++}
++
++if(!function_exists('apc_cache_info') || !($cache=@apc_cache_info($cache_mode))) {
++      echo "No cache info available.  APC does not appear to be running.";
++  exit;
++}
++
++$cache_user = apc_cache_info('user', 1);  
++$mem=apc_sma_info();
++if(!$cache['num_hits']) { $cache['num_hits']=1; $time++; }  // Avoid division by 0 errors on a cache clear
++
++// don't cache this page
++//
++header("Cache-Control: no-store, no-cache, must-revalidate");  // HTTP/1.1
++header("Cache-Control: post-check=0, pre-check=0", false);
++header("Pragma: no-cache");                                    // HTTP/1.0
++
++function duration($ts) {
++    global $time;
++    $years = (int)((($time - $ts)/(7*86400))/52.177457);
++    $rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400));
++    $weeks = (int)(($rem)/(7*86400));
++    $days = (int)(($rem)/86400) - $weeks*7;
++    $hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24;
++    $mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60;
++    $str = '';
++    if($years==1) $str .= "$years year, ";
++    if($years>1) $str .= "$years years, ";
++    if($weeks==1) $str .= "$weeks week, ";
++    if($weeks>1) $str .= "$weeks weeks, ";
++    if($days==1) $str .= "$days day,";
++    if($days>1) $str .= "$days days,";
++    if($hours == 1) $str .= " $hours hour and";
++    if($hours>1) $str .= " $hours hours and";
++    if($mins == 1) $str .= " 1 minute";
++    else $str .= " $mins minutes";
++    return $str;
++}
++
++// create graphics
++//
++function graphics_avail() {
++      return extension_loaded('gd');
++}
++if (isset($MYREQUEST['IMG']))
++{
++      if (!graphics_avail()) {
++              exit(0);
++      }
++
++      function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) {
++              $r=$diameter/2;
++              $w=deg2rad((360+$start+($end-$start)/2)%360);
++
++              
++              if (function_exists("imagefilledarc")) {
++                      // exists only if GD 2.0.1 is avaliable
++                      imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE);
++                      imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE);
++                      imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED);
++              } else {
++                      imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2);
++                      imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
++                      imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
++                      imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1))   * $r, $centerY + sin(deg2rad($end))   * $r, $color2);
++                      imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end))   * $r, $centerY + sin(deg2rad($end))   * $r, $color2);
++                      imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2);
++              }
++              if ($text) {
++                      if ($placeindex>0) {
++                              imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1);
++                              imagestring($im,4,$diameter, $placeindex*12,$text,$color1);     
++                              
++                      } else {
++                              imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1);
++                      }
++              }
++      } 
++
++      function text_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$text,$placeindex=0) {
++              $r=$diameter/2;
++              $w=deg2rad((360+$start+($end-$start)/2)%360);
++
++              if ($placeindex>0) {
++                      imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1);
++                      imagestring($im,4,$diameter, $placeindex*12,$text,$color1);     
++                              
++              } else {
++                      imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1);
++              }
++      } 
++      
++      function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') {
++              global $col_black;
++              $x1=$x+$w-1;
++              $y1=$y+$h-1;
++
++              imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black);
++              if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2);
++              else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2);
++              imagerectangle($im, $x, $y1, $x1, $y, $color1);
++              if ($text) {
++                      if ($placeindex>0) {
++                      
++                              if ($placeindex<16)
++                              {
++                                      $px=5;
++                                      $py=$placeindex*12+6;
++                                      imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2);
++                                      imageline($im,$x,$y+$h/2,$px+90,$py,$color2);
++                                      imagestring($im,2,$px,$py-6,$text,$color1);     
++                                      
++                              } else {
++                                      if ($placeindex<31) {
++                                              $px=$x+40*2;
++                                              $py=($placeindex-15)*12+6;
++                                      } else {
++                                              $px=$x+40*2+100*intval(($placeindex-15)/15);
++                                              $py=($placeindex%15)*12+6;
++                                      }
++                                      imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2);
++                                      imageline($im,$x+$w,$y+$h/2,$px,$py,$color2);
++                                      imagestring($im,2,$px+2,$py-6,$text,$color1);   
++                              }
++                      } else {
++                              imagestring($im,4,$x+5,$y1-16,$text,$color1);
++                      }
++              }
++      }
++
++
++      $size = GRAPH_SIZE; // image size
++      if ($MYREQUEST['IMG']==3)
++              $image = imagecreate(2*$size+150, $size+10);
++      else
++              $image = imagecreate($size+50, $size+10);
++
++      $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
++      $col_red   = imagecolorallocate($image, 0xD0, 0x60,  0x30);
++      $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60);
++      $col_black = imagecolorallocate($image,   0,   0,   0);
++      imagecolortransparent($image,$col_white);
++
++      switch ($MYREQUEST['IMG']) {
++      
++      case 1:
++              $s=$mem['num_seg']*$mem['seg_size'];
++              $a=$mem['avail_mem'];
++              $x=$y=$size/2;
++              $fuzz = 0.000001;
++
++              // This block of code creates the pie chart.  It is a lot more complex than you
++              // would expect because we try to visualize any memory fragmentation as well.
++              $angle_from = 0;
++              $string_placement=array();
++              for($i=0; $i<$mem['num_seg']; $i++) {   
++                      $ptr = 0;
++                      $free = $mem['block_lists'][$i];
++                      foreach($free as $block) {
++                              if($block['offset']!=$ptr) {       // Used block
++                                      $angle_to = $angle_from+($block['offset']-$ptr)/$s;
++                                      if(($angle_to+$fuzz)>1) $angle_to = 1;
++                                      fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red);
++                                      if (($angle_to-$angle_from)>0.05) {
++                                              array_push($string_placement, array($angle_from,$angle_to));
++                                      }
++                                      $angle_from = $angle_to;
++                              }
++                              $angle_to = $angle_from+($block['size'])/$s;
++                              if(($angle_to+$fuzz)>1) $angle_to = 1;
++                              fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_green);
++                              if (($angle_to-$angle_from)>0.05) {
++                                      array_push($string_placement, array($angle_from,$angle_to));
++                              }
++                              $angle_from = $angle_to;
++                              $ptr = $block['offset']+$block['size'];
++                      }
++                      if ($ptr < $mem['seg_size']) { // memory at the end 
++                              $angle_to = $angle_from + ($mem['seg_size'] - $ptr)/$s;
++                              if(($angle_to+$fuzz)>1) $angle_to = 1;
++                              fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red);
++                              if (($angle_to-$angle_from)>0.05) {
++                                      array_push($string_placement, array($angle_from,$angle_to));
++                              }
++                      }
++              }
++              foreach ($string_placement as $angle) {
++                      text_arc($image,$x,$y,$size,$angle[0]*360,$angle[1]*360,$col_black,bsize($s*($angle[1]-$angle[0])));
++              }
++              break;
++              
++      case 2: 
++              $s=$cache['num_hits']+$cache['num_misses'];
++              $a=$cache['num_hits'];
++              
++              fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s));
++              fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s));
++              break;
++              
++      case 3:
++              $s=$mem['num_seg']*$mem['seg_size'];
++              $a=$mem['avail_mem'];
++              $x=130;
++              $y=1;
++              $j=1;
++
++              // This block of code creates the bar chart.  It is a lot more complex than you
++              // would expect because we try to visualize any memory fragmentation as well.
++              for($i=0; $i<$mem['num_seg']; $i++) {   
++                      $ptr = 0;
++                      $free = $mem['block_lists'][$i];
++                      foreach($free as $block) {
++                              if($block['offset']!=$ptr) {       // Used block
++                                      $h=(GRAPH_SIZE-5)*($block['offset']-$ptr)/$s;
++                                      if ($h>0) {
++                                                $j++;
++                                              if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($block['offset']-$ptr),$j);
++                                                else fill_box($image,$x,$y,50,$h,$col_black,$col_red);
++                                        }
++                                      $y+=$h;
++                              }
++                              $h=(GRAPH_SIZE-5)*($block['size'])/$s;
++                              if ($h>0) {
++                                        $j++;
++                                      if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_green,bsize($block['size']),$j);
++                                      else fill_box($image,$x,$y,50,$h,$col_black,$col_green);
++                                }
++                              $y+=$h;
++                              $ptr = $block['offset']+$block['size'];
++                      }
++                      if ($ptr < $mem['seg_size']) { // memory at the end 
++                              $h = (GRAPH_SIZE-5) * ($mem['seg_size'] - $ptr) / $s;
++                              if ($h > 0) {
++                                      fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($mem['seg_size']-$ptr),$j++);
++                              }
++                      }
++              }
++              break;
++      case 4: 
++              $s=$cache['num_hits']+$cache['num_misses'];
++              $a=$cache['num_hits'];
++                      
++              fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s));
++              fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s));
++              break;
++      
++      }
++      header("Content-type: image/png");
++      imagepng($image);
++      exit;
++}
++
++// pretty printer for byte values
++//
++function bsize($s) {
++      foreach (array('','K','M','G') as $i => $k) {
++              if ($s < 1024) break;
++              $s/=1024;
++      }
++      return sprintf("%5.1f %sBytes",$s,$k);
++}
++
++// sortable table header in "scripts for this host" view
++function sortheader($key,$name,$extra='') {
++      global $MYREQUEST, $MY_SELF_WO_SORT;
++      
++      if ($MYREQUEST['SORT1']==$key) {
++              $MYREQUEST['SORT2'] = $MYREQUEST['SORT2']=='A' ? 'D' : 'A';
++      }
++      return "<a class=sortable href=\"$MY_SELF_WO_SORT$extra&SORT1=$key&SORT2=".$MYREQUEST['SORT2']."\">$name</a>";
++
++}
++
++// create menu entry 
++function menu_entry($ob,$title) {
++      global $MYREQUEST,$MY_SELF;
++      if ($MYREQUEST['OB']!=$ob) {
++              return "<li><a href=\"$MY_SELF&OB=$ob\">$title</a></li>";
++      } else if (empty($MYREQUEST['SH'])) {
++              return "<li><span class=active>$title</span></li>";
++      } else {
++              return "<li><a class=\"child_active\" href=\"$MY_SELF&OB=$ob\">$title</a></li>";        
++      }
++}
++
++function put_login_link($s="Login")
++{
++      global $MY_SELF,$MYREQUEST,$AUTHENTICATED;
++      // needs ADMIN_PASSWORD to be changed!
++      //
++      if (!USE_AUTHENTICATION) {
++              return;
++      } else if (ADMIN_PASSWORD=='password')
++      {
++              print <<<EOB
++                      <a href="#" onClick="javascript:alert('You need to set a password at the top of apc.php before this will work!');return false";>$s</a>
++EOB;
++      } else if ($AUTHENTICATED) {
++              print <<<EOB
++                      '{$_SERVER['PHP_AUTH_USER']}'&nbsp;logged&nbsp;in!
++EOB;
++      } else{
++              print <<<EOB
++                      <a href="$MY_SELF&LO=1&OB={$MYREQUEST['OB']}">$s</a>
++EOB;
++      }
++}
++
++
++?>
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
++<html>
++<head><title>APC INFO <?php echo $host ?></title>
++<style><!--
++body { background:white; font-size:100.01%; margin:0; padding:0; }
++body,p,td,th,input,submit { font-size:0.8em;font-family:arial,helvetica,sans-serif; }
++* html body   {font-size:0.8em}
++* html p      {font-size:0.8em}
++* html td     {font-size:0.8em}
++* html th     {font-size:0.8em}
++* html input  {font-size:0.8em}
++* html submit {font-size:0.8em}
++td { vertical-align:top }
++a { color:black; font-weight:none; text-decoration:none; }
++a:hover { text-decoration:underline; }
++div.content { padding:1em 1em 1em 1em; position:absolute; width:97%; z-index:100; }
++
++
++div.head div.login {
++      position:absolute;
++      right: 1em;
++      top: 1.2em;
++      color:white;
++      width:6em;
++      }
++div.head div.login a {
++      position:absolute;
++      right: 0em;
++      background:rgb(119,123,180);
++      border:solid rgb(102,102,153) 2px;
++      color:white;
++      font-weight:bold;
++      padding:0.1em 0.5em 0.1em 0.5em;
++      text-decoration:none;
++      }
++div.head div.login a:hover {
++      background:rgb(193,193,244);
++      }
++
++h1.apc { background:rgb(153,153,204); margin:0; padding:0.5em 1em 0.5em 1em; }
++* html h1.apc { margin-bottom:-7px; }
++h1.apc a:hover { text-decoration:none; color:rgb(90,90,90); }
++h1.apc div.logo span.logo {
++      background:rgb(119,123,180);
++      color:black;
++      border-right: solid black 1px;
++      border-bottom: solid black 1px;
++      font-style:italic;
++      font-size:1em;
++      padding-left:1.2em;
++      padding-right:1.2em;
++      text-align:right;
++      }
++h1.apc div.logo span.name { color:white; font-size:0.7em; padding:0 0.8em 0 2em; }
++h1.apc div.nameinfo { color:white; display:inline; font-size:0.4em; margin-left: 3em; }
++h1.apc div.copy { color:black; font-size:0.4em; position:absolute; right:1em; }
++hr.apc {
++      background:white;
++      border-bottom:solid rgb(102,102,153) 1px;
++      border-style:none;
++      border-top:solid rgb(102,102,153) 10px;
++      height:12px;
++      margin:0;
++      margin-top:1px;
++      padding:0;
++}
++
++ol,menu { margin:1em 0 0 0; padding:0.2em; margin-left:1em;}
++ol.menu li { display:inline; margin-right:0.7em; list-style:none; font-size:85%}
++ol.menu a {
++      background:rgb(153,153,204);
++      border:solid rgb(102,102,153) 2px;
++      color:white;
++      font-weight:bold;
++      margin-right:0em;
++      padding:0.1em 0.5em 0.1em 0.5em;
++      text-decoration:none;
++      margin-left: 5px;
++      }
++ol.menu a.child_active {
++      background:rgb(153,153,204);
++      border:solid rgb(102,102,153) 2px;
++      color:white;
++      font-weight:bold;
++      margin-right:0em;
++      padding:0.1em 0.5em 0.1em 0.5em;
++      text-decoration:none;
++      border-left: solid black 5px;
++      margin-left: 0px;
++      }
++ol.menu span.active {
++      background:rgb(153,153,204);
++      border:solid rgb(102,102,153) 2px;
++      color:black;
++      font-weight:bold;
++      margin-right:0em;
++      padding:0.1em 0.5em 0.1em 0.5em;
++      text-decoration:none;
++      border-left: solid black 5px;
++      }
++ol.menu span.inactive {
++      background:rgb(193,193,244);
++      border:solid rgb(182,182,233) 2px;
++      color:white;
++      font-weight:bold;
++      margin-right:0em;
++      padding:0.1em 0.5em 0.1em 0.5em;
++      text-decoration:none;
++      margin-left: 5px;
++      }
++ol.menu a:hover {
++      background:rgb(193,193,244);
++      text-decoration:none;
++      }
++      
++      
++div.info {
++      background:rgb(204,204,204);
++      border:solid rgb(204,204,204) 1px;
++      margin-bottom:1em;
++      }
++div.info h2 {
++      background:rgb(204,204,204);
++      color:black;
++      font-size:1em;
++      margin:0;
++      padding:0.1em 1em 0.1em 1em;
++      }
++div.info table {
++      border:solid rgb(204,204,204) 1px;
++      border-spacing:0;
++      width:100%;
++      }
++div.info table th {
++      background:rgb(204,204,204);
++      color:white;
++      margin:0;
++      padding:0.1em 1em 0.1em 1em;
++      }
++div.info table th a.sortable { color:black; }
++div.info table tr.tr-0 { background:rgb(238,238,238); }
++div.info table tr.tr-1 { background:rgb(221,221,221); }
++div.info table td { padding:0.3em 1em 0.3em 1em; }
++div.info table td.td-0 { border-right:solid rgb(102,102,153) 1px; white-space:nowrap; }
++div.info table td.td-n { border-right:solid rgb(102,102,153) 1px; }
++div.info table td h3 {
++      color:black;
++      font-size:1.1em;
++      margin-left:-0.3em;
++      }
++
++div.graph { margin-bottom:1em }
++div.graph h2 { background:rgb(204,204,204);; color:black; font-size:1em; margin:0; padding:0.1em 1em 0.1em 1em; }
++div.graph table { border:solid rgb(204,204,204) 1px; color:black; font-weight:normal; width:100%; }
++div.graph table td.td-0 { background:rgb(238,238,238); }
++div.graph table td.td-1 { background:rgb(221,221,221); }
++div.graph table td { padding:0.2em 1em 0.4em 1em; }
++
++div.div1,div.div2 { margin-bottom:1em; width:35em; }
++div.div3 { position:absolute; left:40em; top:1em; width:580px; }
++//div.div3 { position:absolute; left:37em; top:1em; right:1em; }
++
++div.sorting { margin:1.5em 0em 1.5em 2em }
++.center { text-align:center }
++.aright { position:absolute;right:1em }
++.right { text-align:right }
++.ok { color:rgb(0,200,0); font-weight:bold}
++.failed { color:rgb(200,0,0); font-weight:bold}
++
++span.box {
++      border: black solid 1px;
++      border-right:solid black 2px;
++      border-bottom:solid black 2px;
++      padding:0 0.5em 0 0.5em;
++      margin-right:1em;
++}
++span.green { background:#60F060; padding:0 0.5em 0 0.5em}
++span.red { background:#D06030; padding:0 0.5em 0 0.5em }
++
++div.authneeded {
++      background:rgb(238,238,238);
++      border:solid rgb(204,204,204) 1px;
++      color:rgb(200,0,0);
++      font-size:1.2em;
++      font-weight:bold;
++      padding:2em;
++      text-align:center;
++      }
++      
++input {
++      background:rgb(153,153,204);
++      border:solid rgb(102,102,153) 2px;
++      color:white;
++      font-weight:bold;
++      margin-right:1em;
++      padding:0.1em 0.5em 0.1em 0.5em;
++      }
++//-->
++</style>
++</head>
++<body>
++<div class="head">
++      <h1 class="apc">
++              <div class="logo"><span class="logo"><a href="http://pecl.php.net/package/APC">APC</a></span></div>
++              <div class="nameinfo">Opcode Cache</div>
++      </h1>
++      <div class="login">
++      <?php put_login_link(); ?>
++      </div>
++      <hr class="apc">
++</div>
++<?php
++
++
++// Display main Menu
++echo <<<EOB
++      <ol class=menu>
++      <li><a href="$MY_SELF&OB={$MYREQUEST['OB']}&SH={$MYREQUEST['SH']}">Refresh Data</a></li>
++EOB;
++echo
++      menu_entry(1,'View Host Stats'),
++      menu_entry(2,'System Cache Entries');
++if ($AUTHENTICATED) {
++      echo menu_entry(4,'Per-Directory Entries');
++}
++echo
++      menu_entry(3,'User Cache Entries'),
++      menu_entry(9,'Version Check');
++      
++if ($AUTHENTICATED) {
++      echo <<<EOB
++              <li><a class="aright" href="$MY_SELF&CC=1&OB={$MYREQUEST['OB']}" onClick="javascipt:return confirm('Are you sure?');">Clear $cache_mode Cache</a></li>
++EOB;
++}
++echo <<<EOB
++      </ol>
++EOB;
++
++
++// CONTENT
++echo <<<EOB
++      <div class=content>
++EOB;
++
++// MAIN SWITCH STATEMENT 
++
++switch ($MYREQUEST['OB']) {
++
++
++
++
++
++// -----------------------------------------------
++// Host Stats
++// -----------------------------------------------
++case OB_HOST_STATS:
++      $mem_size = $mem['num_seg']*$mem['seg_size'];
++      $mem_avail= $mem['avail_mem'];
++      $mem_used = $mem_size-$mem_avail;
++      $seg_size = bsize($mem['seg_size']);
++      $req_rate = sprintf("%.2f",($cache['num_hits']+$cache['num_misses'])/($time-$cache['start_time']));
++      $hit_rate = sprintf("%.2f",($cache['num_hits'])/($time-$cache['start_time']));
++      $miss_rate = sprintf("%.2f",($cache['num_misses'])/($time-$cache['start_time']));
++      $insert_rate = sprintf("%.2f",($cache['num_inserts'])/($time-$cache['start_time']));
++      $req_rate_user = sprintf("%.2f",($cache_user['num_hits']+$cache_user['num_misses'])/($time-$cache_user['start_time']));
++      $hit_rate_user = sprintf("%.2f",($cache_user['num_hits'])/($time-$cache_user['start_time']));
++      $miss_rate_user = sprintf("%.2f",($cache_user['num_misses'])/($time-$cache_user['start_time']));
++      $insert_rate_user = sprintf("%.2f",($cache_user['num_inserts'])/($time-$cache_user['start_time']));
++      $apcversion = phpversion('apc');
++      $phpversion = phpversion();
++      $number_files = $cache['num_entries']; 
++    $size_files = bsize($cache['mem_size']);
++      $number_vars = $cache_user['num_entries'];
++    $size_vars = bsize($cache_user['mem_size']);
++      $i=0;
++      echo <<< EOB
++              <div class="info div1"><h2>General Cache Information</h2>
++              <table cellspacing=0><tbody>
++              <tr class=tr-0><td class=td-0>APC Version</td><td>$apcversion</td></tr>
++              <tr class=tr-1><td class=td-0>PHP Version</td><td>$phpversion</td></tr>
++EOB;
++
++      if(!empty($_SERVER['SERVER_NAME']))
++              echo "<tr class=tr-0><td class=td-0>APC Host</td><td>{$_SERVER['SERVER_NAME']} $host</td></tr>\n";
++      if(!empty($_SERVER['SERVER_SOFTWARE']))
++              echo "<tr class=tr-1><td class=td-0>Server Software</td><td>{$_SERVER['SERVER_SOFTWARE']}</td></tr>\n";
++
++      echo <<<EOB
++              <tr class=tr-0><td class=td-0>Shared Memory</td><td>{$mem['num_seg']} Segment(s) with $seg_size 
++    <br/> ({$cache['memory_type']} memory, {$cache['locking_type']} locking)
++    </td></tr>
++EOB;
++      echo   '<tr class=tr-1><td class=td-0>Start Time</td><td>',date(DATE_FORMAT,$cache['start_time']),'</td></tr>';
++      echo   '<tr class=tr-0><td class=td-0>Uptime</td><td>',duration($cache['start_time']),'</td></tr>';
++      echo   '<tr class=tr-1><td class=td-0>File Upload Support</td><td>',$cache['file_upload_progress'],'</td></tr>';
++      echo <<<EOB
++              </tbody></table>
++              </div>
++
++              <div class="info div1"><h2>File Cache Information</h2>
++              <table cellspacing=0><tbody>
++              <tr class=tr-0><td class=td-0>Cached Files</td><td>$number_files ($size_files)</td></tr>
++              <tr class=tr-1><td class=td-0>Hits</td><td>{$cache['num_hits']}</td></tr>
++              <tr class=tr-0><td class=td-0>Misses</td><td>{$cache['num_misses']}</td></tr>
++              <tr class=tr-1><td class=td-0>Request Rate (hits, misses)</td><td>$req_rate cache requests/second</td></tr>
++              <tr class=tr-0><td class=td-0>Hit Rate</td><td>$hit_rate cache requests/second</td></tr>
++              <tr class=tr-1><td class=td-0>Miss Rate</td><td>$miss_rate cache requests/second</td></tr>
++              <tr class=tr-0><td class=td-0>Insert Rate</td><td>$insert_rate cache requests/second</td></tr>
++              <tr class=tr-1><td class=td-0>Cache full count</td><td>{$cache['expunges']}</td></tr>
++              </tbody></table>
++              </div>
++
++              <div class="info div1"><h2>User Cache Information</h2>
++              <table cellspacing=0><tbody>
++    <tr class=tr-0><td class=td-0>Cached Variables</td><td>$number_vars ($size_vars)</td></tr>
++              <tr class=tr-1><td class=td-0>Hits</td><td>{$cache_user['num_hits']}</td></tr>
++              <tr class=tr-0><td class=td-0>Misses</td><td>{$cache_user['num_misses']}</td></tr>
++              <tr class=tr-1><td class=td-0>Request Rate (hits, misses)</td><td>$req_rate_user cache requests/second</td></tr>
++              <tr class=tr-0><td class=td-0>Hit Rate</td><td>$hit_rate_user cache requests/second</td></tr>
++              <tr class=tr-1><td class=td-0>Miss Rate</td><td>$miss_rate_user cache requests/second</td></tr>
++              <tr class=tr-0><td class=td-0>Insert Rate</td><td>$insert_rate_user cache requests/second</td></tr>
++              <tr class=tr-1><td class=td-0>Cache full count</td><td>{$cache_user['expunges']}</td></tr>
++
++              </tbody></table>
++              </div>
++
++              <div class="info div2"><h2>Runtime Settings</h2><table cellspacing=0><tbody>
++EOB;
++
++      $j = 0;
++      foreach (ini_get_all('apc') as $k => $v) {
++              echo "<tr class=tr-$j><td class=td-0>",$k,"</td><td>",str_replace(',',',<br />',$v['local_value']),"</td></tr>\n";
++              $j = 1 - $j;
++      }
++
++      if($mem['num_seg']>1 || $mem['num_seg']==1 && count($mem['block_lists'][0])>1)
++              $mem_note = "Memory Usage<br /><font size=-2>(multiple slices indicate fragments)</font>";
++      else
++              $mem_note = "Memory Usage";
++
++      echo <<< EOB
++              </tbody></table>
++              </div>
++
++              <div class="graph div3"><h2>Host Status Diagrams</h2>
++              <table cellspacing=0><tbody>
++EOB;
++      $size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10);
++      echo <<<EOB
++              <tr>
++              <td class=td-0>$mem_note</td>
++              <td class=td-1>Hits &amp; Misses</td>
++              </tr>
++EOB;
++
++      echo
++              graphics_avail() ? 
++                        '<tr>'.
++                        "<td class=td-0><img alt=\"\" $size src=\"$PHP_SELF?IMG=1&$time\"></td>".
++                        "<td class=td-1><img alt=\"\" $size src=\"$PHP_SELF?IMG=2&$time\"></td></tr>\n"
++                      : "",
++              '<tr>',
++              '<td class=td-0><span class="green box">&nbsp;</span>Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size),"</td>\n",
++              '<td class=td-1><span class="green box">&nbsp;</span>Hits: ',$cache['num_hits'].sprintf(" (%.1f%%)",$cache['num_hits']*100/($cache['num_hits']+$cache['num_misses'])),"</td>\n",
++              '</tr>',
++              '<tr>',
++              '<td class=td-0><span class="red box">&nbsp;</span>Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size),"</td>\n",
++              '<td class=td-1><span class="red box">&nbsp;</span>Misses: ',$cache['num_misses'].sprintf(" (%.1f%%)",$cache['num_misses']*100/($cache['num_hits']+$cache['num_misses'])),"</td>\n";
++      echo <<< EOB
++              </tr>
++              </tbody></table>
++
++              <br/>
++              <h2>Detailed Memory Usage and Fragmentation</h2>
++              <table cellspacing=0><tbody>
++              <tr>
++              <td class=td-0 colspan=2><br/>
++EOB;
++
++      // Fragementation: (freeseg - 1) / total_seg
++      $nseg = $freeseg = $fragsize = $freetotal = 0;
++      for($i=0; $i<$mem['num_seg']; $i++) {
++              $ptr = 0;
++              foreach($mem['block_lists'][$i] as $block) {
++                      if ($block['offset'] != $ptr) {
++                              ++$nseg;
++                      }
++                      $ptr = $block['offset'] + $block['size'];
++                        /* Only consider blocks <5M for the fragmentation % */
++                        if($block['size']<(5*1024*1024)) $fragsize+=$block['size'];
++                        $freetotal+=$block['size'];
++              }
++              $freeseg += count($mem['block_lists'][$i]);
++      }
++      
++      if ($freeseg > 1) {
++              $frag = sprintf("%.2f%% (%s out of %s in %d fragments)", ($fragsize/$freetotal)*100,bsize($fragsize),bsize($freetotal),$freeseg);
++      } else {
++              $frag = "0%";
++      }
++
++      if (graphics_avail()) {
++              $size='width='.(2*GRAPH_SIZE+150).' height='.(GRAPH_SIZE+10);
++              echo <<<EOB
++                      <img alt="" $size src="$PHP_SELF?IMG=3&$time">
++EOB;
++      }
++      echo <<<EOB
++              </br>Fragmentation: $frag
++              </td>
++              </tr>
++EOB;
++        if(isset($mem['adist'])) {
++          foreach($mem['adist'] as $i=>$v) {
++            $cur = pow(2,$i); $nxt = pow(2,$i+1)-1;
++            if($i==0) $range = "1";
++            else $range = "$cur - $nxt";
++            echo "<tr><th align=right>$range</th><td align=right>$v</td></tr>\n";
++          }
++        }
++        echo <<<EOB
++              </tbody></table>
++              </div>
++EOB;
++              
++      break;
++
++
++// -----------------------------------------------
++// User Cache Entries
++// -----------------------------------------------
++case OB_USER_CACHE:
++      if (!$AUTHENTICATED) {
++              echo '<div class="authneeded">You need to login to see the user values here!<br/>&nbsp;<br/>';
++              put_login_link("Login now!");
++              echo '</div>';
++              break;
++      }
++      $fieldname='info';
++      $fieldheading='User Entry Label';
++      $fieldkey='info';
++
++
++// -----------------------------------------------
++// System Cache Entries               
++// -----------------------------------------------
++case OB_SYS_CACHE:    
++      if (!isset($fieldname))
++      {
++              $fieldname='filename';
++              $fieldheading='Script Filename';
++              if(ini_get("apc.stat")) $fieldkey='inode';
++              else $fieldkey='filename'; 
++      }
++      if (!empty($MYREQUEST['SH']))
++      {
++              echo <<< EOB
++                      <div class="info"><table cellspacing=0><tbody>
++                      <tr><th>Attribute</th><th>Value</th></tr>
++EOB;
++
++              $m=0;
++              foreach($scope_list as $j => $list) {
++                      foreach($cache[$list] as $i => $entry) {
++                              if (md5($entry[$fieldkey])!=$MYREQUEST['SH']) continue;
++                              foreach($entry as $k => $value) {
++                                      if (!$AUTHENTICATED) {
++                                              // hide all path entries if not logged in
++                                              $value=preg_replace('/^.*(\\/|\\\\)/','<i>&lt;hidden&gt;</i>/',$value);
++                                      }
++
++                                      if ($k == "num_hits") {
++                                              $value=sprintf("%s (%.2f%%)",$value,$value*100/$cache['num_hits']);
++                                      }
++                                      if ($k == 'deletion_time') {
++                                              if(!$entry['deletion_time']) $value = "None";
++                                      }
++                                      echo
++                                              "<tr class=tr-$m>",
++                                              "<td class=td-0>",ucwords(preg_replace("/_/"," ",$k)),"</td>",
++                                              "<td class=td-last>",(preg_match("/time/",$k) && $value!='None') ? date(DATE_FORMAT,$value) : $value,"</td>",
++                                              "</tr>";
++                                      $m=1-$m;
++                              }
++                              if($fieldkey=='info') {
++                                      echo "<tr class=tr-$m><td class=td-0>Stored Value</td><td class=td-last><pre>";
++                                      $output = var_export(apc_fetch($entry[$fieldkey]),true);
++                                      echo htmlspecialchars($output);
++                                      echo "</pre></td></tr>\n";
++                              }
++                              break;
++                      }
++              }
++
++              echo <<<EOB
++                      </tbody></table>
++                      </div>
++EOB;
++              break;
++      }
++
++      $cols=6;
++      echo <<<EOB
++              <div class=sorting><form>Scope:
++              <input type=hidden name=OB value={$MYREQUEST['OB']}>
++              <select name=SCOPE>
++EOB;
++      echo 
++              "<option value=A",$MYREQUEST['SCOPE']=='A' ? " selected":"",">Active</option>",
++              "<option value=D",$MYREQUEST['SCOPE']=='D' ? " selected":"",">Deleted</option>",
++              "</select>",
++              ", Sorting:<select name=SORT1>",
++              "<option value=H",$MYREQUEST['SORT1']=='H' ? " selected":"",">Hits</option>",
++              "<option value=Z",$MYREQUEST['SORT1']=='Z' ? " selected":"",">Size</option>",
++              "<option value=S",$MYREQUEST['SORT1']=='S' ? " selected":"",">$fieldheading</option>",
++              "<option value=A",$MYREQUEST['SORT1']=='A' ? " selected":"",">Last accessed</option>",
++              "<option value=M",$MYREQUEST['SORT1']=='M' ? " selected":"",">Last modified</option>",
++              "<option value=C",$MYREQUEST['SORT1']=='C' ? " selected":"",">Created at</option>",
++              "<option value=D",$MYREQUEST['SORT1']=='D' ? " selected":"",">Deleted at</option>";
++      if($fieldname=='info') echo
++              "<option value=D",$MYREQUEST['SORT1']=='T' ? " selected":"",">Timeout</option>";
++      echo 
++              '</select>',
++              '<select name=SORT2>',
++              '<option value=D',$MYREQUEST['SORT2']=='D' ? ' selected':'','>DESC</option>',
++              '<option value=A',$MYREQUEST['SORT2']=='A' ? ' selected':'','>ASC</option>',
++              '</select>',
++              '<select name=COUNT onChange="form.submit()">',
++              '<option value=10 ',$MYREQUEST['COUNT']=='10' ? ' selected':'','>Top 10</option>',
++              '<option value=20 ',$MYREQUEST['COUNT']=='20' ? ' selected':'','>Top 20</option>',
++              '<option value=50 ',$MYREQUEST['COUNT']=='50' ? ' selected':'','>Top 50</option>',
++              '<option value=100',$MYREQUEST['COUNT']=='100'? ' selected':'','>Top 100</option>',
++              '<option value=150',$MYREQUEST['COUNT']=='150'? ' selected':'','>Top 150</option>',
++              '<option value=200',$MYREQUEST['COUNT']=='200'? ' selected':'','>Top 200</option>',
++              '<option value=500',$MYREQUEST['COUNT']=='500'? ' selected':'','>Top 500</option>',
++              '<option value=0  ',$MYREQUEST['COUNT']=='0'  ? ' selected':'','>All</option>',
++              '</select>',
++    '&nbsp; Search: <input name=SEARCH value="',$MYREQUEST['SEARCH'],'" type=text size=25/>',
++              '&nbsp;<input type=submit value="GO!">',
++              '</form></div>',
++
++              '<div class="info"><table cellspacing=0><tbody>',
++              '<tr>',
++              '<th>',sortheader('S',$fieldheading,  "&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('H','Hits',         "&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('Z','Size',         "&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('A','Last accessed',"&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('M','Last modified',"&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('C','Created at',   "&OB=".$MYREQUEST['OB']),'</th>';
++
++      if($fieldname=='info') {
++              $cols+=2;
++               echo '<th>',sortheader('T','Timeout',"&OB=".$MYREQUEST['OB']),'</th>';
++      }
++      echo '<th>',sortheader('D','Deleted at',"&OB=".$MYREQUEST['OB']),'</th></tr>';
++
++      // builds list with alpha numeric sortable keys
++      //
++      $list = array();
++      foreach($cache[$scope_list[$MYREQUEST['SCOPE']]] as $i => $entry) {
++              switch($MYREQUEST['SORT1']) {
++                      case 'A': $k=sprintf('%015d-',$entry['access_time']);   break;
++                      case 'H': $k=sprintf('%015d-',$entry['num_hits']);              break;
++                      case 'Z': $k=sprintf('%015d-',$entry['mem_size']);              break;
++                      case 'M': $k=sprintf('%015d-',$entry['mtime']);                 break;
++                      case 'C': $k=sprintf('%015d-',$entry['creation_time']); break;
++                      case 'T': $k=sprintf('%015d-',$entry['ttl']);                   break;
++                      case 'D': $k=sprintf('%015d-',$entry['deletion_time']); break;
++                      case 'S': $k='';                                                                                break;
++              }
++              if (!$AUTHENTICATED) {
++                      // hide all path entries if not logged in
++                      $list[$k.$entry[$fieldname]]=preg_replace('/^.*(\\/|\\\\)/','<i>&lt;hidden&gt;</i>/',$entry);
++              } else {
++                      $list[$k.$entry[$fieldname]]=$entry;
++              }
++      }
++
++      if ($list) {
++              
++              // sort list
++              //
++              switch ($MYREQUEST['SORT2']) {
++                      case "A":       krsort($list);  break;
++                      case "D":       ksort($list);   break;
++              }
++              
++              // output list
++              $i=0;
++              foreach($list as $k => $entry) {
++      if(!$MYREQUEST['SEARCH'] || preg_match('/'.$MYREQUEST['SEARCH'].'/i', $entry[$fieldname]) != 0) {  
++        echo
++          '<tr class=tr-',$i%2,'>',
++          "<td class=td-0><a href=\"$MY_SELF&OB=",$MYREQUEST['OB'],"&SH=",md5($entry[$fieldkey]),"\">",$entry[$fieldname],'</a></td>',
++          '<td class="td-n center">',$entry['num_hits'],'</td>',
++          '<td class="td-n right">',$entry['mem_size'],'</td>',
++          '<td class="td-n center">',date(DATE_FORMAT,$entry['access_time']),'</td>',
++          '<td class="td-n center">',date(DATE_FORMAT,$entry['mtime']),'</td>',
++          '<td class="td-n center">',date(DATE_FORMAT,$entry['creation_time']),'</td>';
++
++        if($fieldname=='info') {
++          if($entry['ttl'])
++            echo '<td class="td-n center">'.$entry['ttl'].' seconds</td>';
++          else
++            echo '<td class="td-n center">None</td>';
++        }
++        echo
++          '<td class="td-last center">',$entry['deletion_time'] ? date(DATE_FORMAT,$entry['deletion_time']) : '-','</td>',
++          '</tr>';
++        $i++;
++        if ($i == $MYREQUEST['COUNT'])
++          break;
++      }
++              }
++              
++      } else {
++              echo '<tr class=tr-0><td class="center" colspan=',$cols,'><i>No data</i></td></tr>';
++      }
++      echo <<< EOB
++              </tbody></table>
++EOB;
++
++      if ($list && $i < count($list)) {
++              echo "<a href=\"$MY_SELF&OB=",$MYREQUEST['OB'],"&COUNT=0\"><i>",count($list)-$i,' more available...</i></a>';
++      }
++
++      echo <<< EOB
++              </div>
++EOB;
++      break;
++
++
++// -----------------------------------------------
++// Per-Directory System Cache Entries
++// -----------------------------------------------
++case OB_SYS_CACHE_DIR:        
++      if (!$AUTHENTICATED) {
++              break;
++      }
++
++      echo <<<EOB
++              <div class=sorting><form>Scope:
++              <input type=hidden name=OB value={$MYREQUEST['OB']}>
++              <select name=SCOPE>
++EOB;
++      echo 
++              "<option value=A",$MYREQUEST['SCOPE']=='A' ? " selected":"",">Active</option>",
++              "<option value=D",$MYREQUEST['SCOPE']=='D' ? " selected":"",">Deleted</option>",
++              "</select>",
++              ", Sorting:<select name=SORT1>",
++              "<option value=H",$MYREQUEST['SORT1']=='H' ? " selected":"",">Total Hits</option>",
++              "<option value=Z",$MYREQUEST['SORT1']=='Z' ? " selected":"",">Total Size</option>",
++              "<option value=T",$MYREQUEST['SORT1']=='T' ? " selected":"",">Number of Files</option>",
++              "<option value=S",$MYREQUEST['SORT1']=='S' ? " selected":"",">Directory Name</option>",
++              "<option value=A",$MYREQUEST['SORT1']=='A' ? " selected":"",">Avg. Size</option>",
++              "<option value=C",$MYREQUEST['SORT1']=='C' ? " selected":"",">Avg. Hits</option>",
++              '</select>',
++              '<select name=SORT2>',
++              '<option value=D',$MYREQUEST['SORT2']=='D' ? ' selected':'','>DESC</option>',
++              '<option value=A',$MYREQUEST['SORT2']=='A' ? ' selected':'','>ASC</option>',
++              '</select>',
++              '<select name=COUNT onChange="form.submit()">',
++              '<option value=10 ',$MYREQUEST['COUNT']=='10' ? ' selected':'','>Top 10</option>',
++              '<option value=20 ',$MYREQUEST['COUNT']=='20' ? ' selected':'','>Top 20</option>',
++              '<option value=50 ',$MYREQUEST['COUNT']=='50' ? ' selected':'','>Top 50</option>',
++              '<option value=100',$MYREQUEST['COUNT']=='100'? ' selected':'','>Top 100</option>',
++              '<option value=150',$MYREQUEST['COUNT']=='150'? ' selected':'','>Top 150</option>',
++              '<option value=200',$MYREQUEST['COUNT']=='200'? ' selected':'','>Top 200</option>',
++              '<option value=500',$MYREQUEST['COUNT']=='500'? ' selected':'','>Top 500</option>',
++              '<option value=0  ',$MYREQUEST['COUNT']=='0'  ? ' selected':'','>All</option>',
++              '</select>',
++              ", Group By Dir Level:<select name=AGGR>",
++              "<option value='' selected>None</option>";
++              for ($i = 1; $i < 10; $i++)
++                      echo "<option value=$i",$MYREQUEST['AGGR']==$i ? " selected":"",">$i</option>";
++              echo '</select>',
++              '&nbsp;<input type=submit value="GO!">',
++              '</form></div>',
++
++              '<div class="info"><table cellspacing=0><tbody>',
++              '<tr>',
++              '<th>',sortheader('S','Directory Name', "&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('T','Number of Files',"&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('H','Total Hits',     "&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('Z','Total Size',     "&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('C','Avg. Hits',      "&OB=".$MYREQUEST['OB']),'</th>',
++              '<th>',sortheader('A','Avg. Size',      "&OB=".$MYREQUEST['OB']),'</th>',
++              '</tr>';
++
++      // builds list with alpha numeric sortable keys
++      //
++      $tmp = $list = array();
++      foreach($cache[$scope_list[$MYREQUEST['SCOPE']]] as $entry) {
++              $n = dirname($entry['filename']);
++              if ($MYREQUEST['AGGR'] > 0) {
++                      $n = preg_replace("!^(/?(?:[^/\\\\]+[/\\\\]){".($MYREQUEST['AGGR']-1)."}[^/\\\\]*).*!", "$1", $n);
++              }
++              if (!isset($tmp[$n])) {
++                      $tmp[$n] = array('hits'=>0,'size'=>0,'ents'=>0);
++              }
++              $tmp[$n]['hits'] += $entry['num_hits'];
++              $tmp[$n]['size'] += $entry['mem_size'];
++              ++$tmp[$n]['ents'];
++      }
++
++      foreach ($tmp as $k => $v) {
++              switch($MYREQUEST['SORT1']) {
++                      case 'A': $kn=sprintf('%015d-',$v['size'] / $v['ents']);break;
++                      case 'T': $kn=sprintf('%015d-',$v['ents']);             break;
++                      case 'H': $kn=sprintf('%015d-',$v['hits']);             break;
++                      case 'Z': $kn=sprintf('%015d-',$v['size']);             break;
++                      case 'C': $kn=sprintf('%015d-',$v['hits'] / $v['ents']);break;
++                      case 'S': $kn = $k;                                     break;
++              }
++              $list[$kn.$k] = array($k, $v['ents'], $v['hits'], $v['size']);
++      }
++
++      if ($list) {
++              
++              // sort list
++              //
++              switch ($MYREQUEST['SORT2']) {
++                      case "A":       krsort($list);  break;
++                      case "D":       ksort($list);   break;
++              }
++              
++              // output list
++              $i = 0;
++              foreach($list as $entry) {
++                      echo
++                              '<tr class=tr-',$i%2,'>',
++                              "<td class=td-0>",$entry[0],'</a></td>',
++                              '<td class="td-n center">',$entry[1],'</td>',
++                              '<td class="td-n center">',$entry[2],'</td>',
++                              '<td class="td-n center">',$entry[3],'</td>',
++                              '<td class="td-n center">',round($entry[2] / $entry[1]),'</td>',
++                              '<td class="td-n center">',round($entry[3] / $entry[1]),'</td>',
++                              '</tr>';
++
++                      if (++$i == $MYREQUEST['COUNT']) break;
++              }
++              
++      } else {
++              echo '<tr class=tr-0><td class="center" colspan=6><i>No data</i></td></tr>';
++      }
++      echo <<< EOB
++              </tbody></table>
++EOB;
++
++      if ($list && $i < count($list)) {
++              echo "<a href=\"$MY_SELF&OB=",$MYREQUEST['OB'],"&COUNT=0\"><i>",count($list)-$i,' more available...</i></a>';
++      }
++
++      echo <<< EOB
++              </div>
++EOB;
++      break;
++
++// -----------------------------------------------
++// Version check
++// -----------------------------------------------
++case OB_VERSION_CHECK:
++      echo <<<EOB
++              <div class="info"><h2>APC Version Information</h2>
++              <table cellspacing=0><tbody>
++              <tr>
++              <th></th>
++              </tr>
++EOB;
++
++      $rss = @file_get_contents("http://pecl.php.net/feeds/pkg_apc.rss");
++      if (!$rss) {
++              echo '<tr class="td-last center"><td>Unable to fetch version information.</td></tr>';
++      } else {
++              $apcversion = phpversion('apc');
++
++              preg_match('!<title>APC ([0-9.]+)</title>!', $rss, $match);
++              echo '<tr class="tr-0 center"><td>';
++              if (version_compare($apcversion, $match[1], '>=')) {
++                      echo '<div class="ok">You are running the latest version of APC ('.$apcversion.')</div>';
++                      $i = 3;
++              } else {
++                      echo '<div class="failed">You are running an older version of APC ('.$apcversion.'), 
++                              newer version '.$match[1].' is available at <a href="http://pecl.php.net/package/APC/'.$match[1].'">
++                              http://pecl.php.net/package/APC/'.$match[1].'</a>
++                              </div>';
++                      $i = -1;
++              }
++              echo '</td></tr>';
++              echo '<tr class="tr-0"><td><h3>Change Log:</h3><br/>';
++
++              preg_match_all('!<(title|description)>([^<]+)</\\1>!', $rss, $match);
++              next($match[2]); next($match[2]);
++
++              while (list(,$v) = each($match[2])) {
++                      list(,$ver) = explode(' ', $v, 2);
++                      if ($i < 0 && version_compare($apcversion, $ver, '>=')) {
++                              break;
++                      } else if (!$i--) {
++                              break;
++                      }
++                      echo "<b><a href=\"http://pecl.php.net/package/APC/$ver\">".htmlspecialchars($v)."</a></b><br><blockquote>";
++                      echo nl2br(htmlspecialchars(current($match[2])))."</blockquote>";
++                      next($match[2]);
++              }
++              echo '</td></tr>';
++      }
++      echo <<< EOB
++              </tbody></table>
++              </div>
++EOB;
++      break;
++
++}
++
++echo <<< EOB
++      </div>
++EOB;
++
++?>
++
++<!-- <?php echo "\nBased on APCGUI By R.Becker\n$VERSION\n"?> -->
++</body>
++</html>
+diff -ruN php-5.1.6.old/ext/apc/apc_php.h php-5.1.6/ext/APC/apc_php.h
+--- php-5.1.6.old/ext/apc/apc_php.h    1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_php.h        2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,71 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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_php.h,v 3.10 2006/11/16 20:24:48 gopalv Exp $ */
++
++#ifndef APC_PHP_H
++#define APC_PHP_H
++
++/*
++ * The purpose of this header file is to include all PHP and Zend headers that
++ * are typically needed elsewhere in APC. This makes it easy to insure that
++ * all required headers are available.
++ */
++
++#include "php.h"
++#include "zend.h"
++#include "zend_API.h"
++#include "zend_compile.h"
++#include "zend_hash.h"
++#include "zend_extensions.h"
++
++#if ZEND_MODULE_API_NO > 20050922
++#define ZEND_ENGINE_2_2
++#endif
++#if ZEND_MODULE_API_NO > 20050921
++#define ZEND_ENGINE_2_1
++#endif
++#ifdef ZEND_ENGINE_2_1
++#include "zend_vm.h"
++#endif
++
++#include "rfc1867.h"
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_pthreadmutex.c php-5.1.6/ext/APC/apc_pthreadmutex.c
+--- php-5.1.6.old/ext/apc/apc_pthreadmutex.c   1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_pthreadmutex.c       2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,104 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Brian Shire <shire@php.net>                                 |
++  +----------------------------------------------------------------------+
++
++ */
++
++/* $Id: apc_pthreadmutex.c,v 3.2 2007/02/15 21:40:45 shire Exp $ */
++
++#include "apc_pthreadmutex.h"
++
++#ifdef APC_PTHREADMUTEX_LOCKS
++
++pthread_mutex_t *apc_pthreadmutex_create(pthread_mutex_t *lock) 
++{ 
++    int result;
++    pthread_mutexattr_t* attr;
++    attr = malloc(sizeof(pthread_mutexattr_t));
++
++    result = pthread_mutexattr_init(attr);
++    if(result == ENOMEM) {
++        apc_eprint("pthread mutex error: Insufficient memory exists to create the mutex attribute object.");
++    } else if(result == EINVAL) {
++        apc_eprint("pthread mutex error: attr does not point to writeable memory.");
++    } else if(result == EFAULT) {
++        apc_eprint("pthread mutex error: attr is an invalid pointer.");
++    } 
++
++    /* pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ERRORCHECK); */
++    result = pthread_mutexattr_setpshared(attr, PTHREAD_PROCESS_SHARED);
++    if(result == EINVAL) {
++        apc_eprint("pthread mutex error: attr is not an initialized mutex attribute object, or pshared is not a valid process-shared state setting.");
++    } else if(result == EFAULT) {
++        apc_eprint("pthread mutex error: attr is an invalid pointer.");
++    } else if(result == ENOTSUP) {
++        apc_eprint("pthread mutex error: pshared was set to PTHREAD_PROCESS_SHARED.");
++    }
++
++    if(pthread_mutex_init(lock, attr)) { 
++        apc_eprint("unable to initialize pthread lock");
++    }
++    return lock;
++}
++
++void apc_pthreadmutex_destroy(pthread_mutex_t *lock)
++{
++    return; /* we don't actually destroy the mutex, as it would destroy it for all processes */
++}
++
++void apc_pthreadmutex_lock(pthread_mutex_t *lock)
++{
++    int result;
++    result = pthread_mutex_lock(lock);
++    if(result == EINVAL) {
++        apc_eprint("unable to obtain pthread lock (EINVAL)");
++    } else if(result == EDEADLK) {
++        apc_eprint("unable to obtain pthread lock (EDEADLK)");
++    }  
++}
++
++void apc_pthreadmutex_unlock(pthread_mutex_t *lock)
++{
++    if(pthread_mutex_unlock(lock)) {
++        apc_eprint("unable to unlock pthread lock");
++    }
++}
++
++zend_bool apc_pthreadmutex_nonblocking_lock(pthread_mutex_t *lock)
++{
++    int rval;
++    rval = pthread_mutex_trylock(lock);
++    if(rval == EBUSY) {     /* Lock is already held */
++        return 0;
++    } else if(rval == 0) {  /* Obtained lock */
++        return 1;
++    } else {                /* Other error */
++        apc_eprint("unable to obtain pthread trylock");
++        return 0;
++    }
++}
++
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_pthreadmutex.h php-5.1.6/ext/APC/apc_pthreadmutex.h
+--- php-5.1.6.old/ext/apc/apc_pthreadmutex.h   1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_pthreadmutex.h       2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,48 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Brian Shire <shire@php.net>                                 |
++  +----------------------------------------------------------------------+
++
++ */
++
++/* $Id: apc_pthreadmutex.h,v 3.3 2007/01/28 07:53:57 shire Exp $ */
++
++#ifndef APC_PTHREADMUTEX_H
++#define APC_PTHREADMUTEX_H
++
++#include "apc.h"
++
++#ifdef APC_PTHREADMUTEX_LOCKS 
++
++#include <pthread.h>
++
++pthread_mutex_t *apc_pthreadmutex_create();
++void apc_pthreadmutex_destroy(pthread_mutex_t *lock);
++void apc_pthreadmutex_lock(pthread_mutex_t *lock);
++void apc_pthreadmutex_unlock(pthread_mutex_t *lock);
++zend_bool apc_pthreadmutex_nonblocking_lock(pthread_mutex_t *lock);
++
++#endif
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_rfc1867.c php-5.1.6/ext/APC/apc_rfc1867.c
+--- php-5.1.6.old/ext/apc/apc_rfc1867.c        1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_rfc1867.c    2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,175 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Rasmus Lerdorf <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_rfc1867.c,v 3.4 2007/02/24 11:45:29 rasmus Exp $*/
++
++#include "apc.h"
++#include "rfc1867.h"
++
++#ifdef MULTIPART_EVENT_FORMDATA
++extern int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC);
++
++static double my_time() {
++    struct timeval a;
++    double t;
++    gettimeofday(&a, NULL);
++    t = a.tv_sec + (a.tv_usec/1000000);
++    return t;
++}
++
++void apc_rfc1867_progress(unsigned int event, void *event_data, void **extra TSRMLS_DC) {
++    static char tracking_key[64];
++    static int  key_length = 0;
++    static size_t content_length = 0;
++    static char filename[128];
++    static char name[64];
++    static char *temp_filename=NULL;
++    static int cancel_upload = 0;
++    static double start_time;
++    static size_t bytes_processed = 0;
++    static double rate;
++    zval *track = NULL;
++
++      switch (event) {
++              case MULTIPART_EVENT_START:
++                      {
++                multipart_event_start *data = (multipart_event_start *) event_data;
++                content_length = data->content_length;
++                *tracking_key = '\0';
++                *name = '\0';
++                cancel_upload = 0;
++                temp_filename = NULL;
++                *filename= '\0';
++                key_length = 0;
++                start_time = my_time();
++                bytes_processed = 0;
++                rate = 0;
++                      }
++                      break;
++
++              case MULTIPART_EVENT_FORMDATA:
++                      {
++                multipart_event_formdata *data = (multipart_event_formdata *) event_data;
++
++                              if(data->name && !strncasecmp(data->name,"apc_upload_progress",19) && data->value && data->length && data->length < 58) {
++                    strlcat(tracking_key, "upload_", 63);
++                    strlcat(tracking_key, *data->value, 63);
++                    key_length = data->length+7;
++                    bytes_processed = data->post_bytes_processed;
++                              }
++                      }
++                      break;
++
++              case MULTIPART_EVENT_FILE_START:
++            if(*tracking_key) {
++                multipart_event_file_start *data = (multipart_event_file_start *) event_data;
++
++                bytes_processed = data->post_bytes_processed;
++                strncpy(filename,*data->filename,127);
++                temp_filename = NULL;
++                strncpy(name,data->name,63);
++                ALLOC_INIT_ZVAL(track);
++                array_init(track);
++                add_assoc_long(track, "total", content_length);
++                add_assoc_long(track, "current", bytes_processed);
++                add_assoc_string(track, "filename", filename, 1);
++                add_assoc_string(track, "name", name, 1);
++                add_assoc_long(track, "done", 0);
++                _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC);
++                zval_ptr_dtor(&track);
++            }
++            break;
++
++              case MULTIPART_EVENT_FILE_DATA:
++            if(*tracking_key) {
++                multipart_event_file_data *data = (multipart_event_file_data *) event_data;
++                bytes_processed = data->post_bytes_processed;
++                ALLOC_INIT_ZVAL(track);
++                array_init(track);
++                add_assoc_long(track, "total", content_length);
++                add_assoc_long(track, "current", bytes_processed);
++                add_assoc_string(track, "filename", filename, 1);
++                add_assoc_string(track, "name", name, 1);
++                add_assoc_long(track, "done", 0);
++                _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC);
++                zval_ptr_dtor(&track);
++                      }
++                      break;
++
++              case MULTIPART_EVENT_FILE_END:
++            if(*tracking_key) {
++                multipart_event_file_end *data = (multipart_event_file_end *) event_data;
++                bytes_processed = data->post_bytes_processed;
++                cancel_upload = data->cancel_upload;
++                temp_filename = data->temp_filename;
++                ALLOC_INIT_ZVAL(track);
++                array_init(track);
++                add_assoc_long(track, "total", content_length);
++                add_assoc_long(track, "current", bytes_processed);
++                add_assoc_string(track, "filename", filename, 1);
++                add_assoc_string(track, "name", name, 1);
++                add_assoc_string(track, "temp_filename", temp_filename, 1);
++                add_assoc_long(track, "cancel_upload", cancel_upload);
++                add_assoc_long(track, "done", 0);
++                _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC);
++                zval_ptr_dtor(&track);
++                      }
++                      break;
++
++              case MULTIPART_EVENT_END:
++            if(*tracking_key) {
++                double now = my_time(); 
++                multipart_event_end *data = (multipart_event_end *) event_data;
++                bytes_processed = data->post_bytes_processed;
++                if(now>start_time) rate = 8.0*bytes_processed/(now-start_time);
++                else rate = 8.0*bytes_processed;  /* Too quick */
++                ALLOC_INIT_ZVAL(track);
++                array_init(track);
++                add_assoc_long(track, "total", content_length);
++                add_assoc_long(track, "current", bytes_processed);
++                add_assoc_double(track, "rate", rate);
++                add_assoc_string(track, "filename", filename, 1);
++                add_assoc_string(track, "name", name, 1);
++                add_assoc_string(track, "temp_filename", temp_filename, 1);
++                add_assoc_long(track, "cancel_upload", cancel_upload);
++                add_assoc_long(track, "done", 1);
++                _apc_store(tracking_key, key_length, track, 3600, 0 TSRMLS_CC);
++                zval_ptr_dtor(&track);
++                      }
++                      break;
++      }
++}
++
++#endif
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_sem.c php-5.1.6/ext/APC/apc_sem.c
+--- php-5.1.6.old/ext/apc/apc_sem.c    1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_sem.c        2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,177 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.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_sem.c,v 3.16 2006/03/12 00:31:45 rasmus Exp $ */
++
++#include "apc_sem.h"
++#include "apc.h"
++#include "php.h"
++#include <sys/types.h>
++#include <sys/ipc.h>
++#include <sys/sem.h>
++#include <sys/stat.h>
++#include <unistd.h>
++
++#if HAVE_SEMUN
++/* we have semun, no need to define */
++#else
++#undef HAVE_SEMUN
++union semun {
++    int val;                  /* value for SETVAL */
++    struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
++    unsigned short *array;    /* array for GETALL, SETALL */
++                              /* Linux specific part: */
++    struct seminfo *__buf;    /* buffer for IPC_INFO */
++};
++#define HAVE_SEMUN 1
++#endif
++
++#ifndef SEM_R
++# define SEM_R 0444
++#endif
++#ifndef SEM_A
++# define SEM_A 0222
++#endif
++
++/* always use SEM_UNDO, otherwise we risk deadlock */
++#define USE_SEM_UNDO
++
++#ifdef USE_SEM_UNDO
++# define UNDO SEM_UNDO
++#else
++# define UNDO 0
++#endif
++
++int apc_sem_create(const char* pathname, int proj, int initval)
++{
++    int semid;
++    int perms;
++    union semun arg;
++    key_t key;
++
++    perms = 0777;
++
++    key = IPC_PRIVATE;
++    if (pathname != NULL) {
++        if ((key = ftok(pathname, proj)) < 0) {
++            apc_eprint("apc_sem_create: ftok(%s,%d) failed:", pathname, proj);
++        }
++    }
++    
++    if ((semid = semget(key, 1, IPC_CREAT | IPC_EXCL | perms)) >= 0) {
++        /* sempahore created for the first time, initialize now */
++        arg.val = initval;
++        if (semctl(semid, 0, SETVAL, arg) < 0) {
++            apc_eprint("apc_sem_create: semctl(%d,...) failed:", semid);
++        }
++    }
++    else if (errno == EEXIST) {
++        /* sempahore already exists, don't initialize */
++        if ((semid = semget(key, 1, perms)) < 0) {
++            apc_eprint("apc_sem_create: semget(%u,...) failed:", key);
++        }
++        /* insert <sleazy way to avoid race condition> here */
++    }
++    else {
++        apc_eprint("apc_sem_create: semget(%u,...) failed:", key);
++    }
++
++    return semid;
++}
++
++void apc_sem_destroy(int semid)
++{
++    /* we expect this call to fail often, so we do not check */
++    union semun arg;
++    semctl(semid, 0, IPC_RMID, arg);
++}
++
++void apc_sem_lock(int semid)
++{
++    struct sembuf op;
++
++    op.sem_num = 0;
++    op.sem_op  = -1;
++    op.sem_flg = UNDO;
++
++    if (semop(semid, &op, 1) < 0) {
++        if (errno != EINTR) {
++            apc_eprint("apc_sem_lock: semop(%d) failed:", semid);
++        }
++    }
++}
++
++void apc_sem_unlock(int semid)
++{
++    struct sembuf op;
++
++    op.sem_num = 0;
++    op.sem_op  = 1;
++    op.sem_flg = UNDO;
++
++    if (semop(semid, &op, 1) < 0) {
++        if (errno != EINTR) {
++            apc_eprint("apc_sem_unlock: semop(%d) failed:", semid);
++        }
++    }
++}
++
++void apc_sem_wait_for_zero(int semid)
++{
++    struct sembuf op;
++
++    op.sem_num = 0;
++    op.sem_op  = 0;
++    op.sem_flg = UNDO;
++
++    if (semop(semid, &op, 1) < 0) {
++        if (errno != EINTR) {
++            apc_eprint("apc_sem_waitforzero: semop(%d) failed:", semid);
++        }
++    }
++}
++
++int apc_sem_get_value(int semid)
++{
++    union semun arg;
++    unsigned short val[1];
++
++    arg.array = val;
++    if (semctl(semid, 0, GETALL, arg) < 0) {
++        apc_eprint("apc_sem_getvalue: semctl(%d,...) failed:", semid);
++    }
++    return val[0];
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_sem.h php-5.1.6/ext/APC/apc_sem.h
+--- php-5.1.6.old/ext/apc/apc_sem.h    1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_sem.h        2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,51 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.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_sem.h,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */
++
++#ifndef APC_SEM_H
++#define APC_SEM_H
++
++/* Wrapper functions for SysV sempahores */
++
++extern int apc_sem_create(const char* pathname, int proj, int initval);
++extern void apc_sem_destroy(int semid);
++extern void apc_sem_lock(int semid);
++extern void apc_sem_unlock(int semid);
++extern void apc_sem_wait_for_zero(int semid);
++extern int apc_sem_get_value(int semid);
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_shm.c php-5.1.6/ext/APC/apc_shm.c
+--- php-5.1.6.old/ext/apc/apc_shm.c    1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_shm.c        2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,111 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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_shm.c,v 3.10 2006/05/31 22:24:48 rasmus Exp $ */
++
++#include "apc_shm.h"
++#include "apc.h"
++#include <sys/types.h>
++#ifdef PHP_WIN32
++/* shm functions are available in TSRM */
++#include <tsrm/tsrm_win32.h>
++#define key_t long
++#else
++#include <sys/ipc.h>
++#include <sys/shm.h>
++#include <sys/stat.h>
++#endif
++
++#ifndef SHM_R
++# define SHM_R 0444 /* read permission */
++#endif
++#ifndef SHM_A
++# define SHM_A 0222 /* write permission */
++#endif
++
++int apc_shm_create(const char* pathname, int proj, int size)
++{
++    int shmid;  /* shared memory id */
++    int oflag;  /* permissions on shm */
++    key_t key;  /* shm key returned by ftok */
++
++    key = IPC_PRIVATE;
++#ifndef PHP_WIN32
++      /* no ftok yet for win32 */
++    if (pathname != NULL) {
++        if ((key = ftok(pathname, proj)) < 0) {
++            apc_eprint("apc_shm_create: ftok failed:");
++        }
++    }
++#endif
++
++    oflag = IPC_CREAT | SHM_R | SHM_A;
++    if ((shmid = shmget(key, size, oflag)) < 0) {
++        apc_eprint("apc_shm_create: shmget(%d, %d, %d) failed: %s. It is possible that the chosen SHM segment size is higher than the operation system allows. Linux has usually a default limit of 32MB per segment.", key, size, oflag, strerror(errno));
++    }
++
++    return shmid;
++}
++
++void apc_shm_destroy(int shmid)
++{
++    /* we expect this call to fail often, so we do not check */
++    shmctl(shmid, IPC_RMID, 0);
++}
++
++void* apc_shm_attach(int shmid)
++{
++    void* shmaddr;  /* the shared memory address */
++
++    if ((int)(shmaddr = shmat(shmid, 0, 0)) == -1) {
++        apc_eprint("apc_shm_attach: shmat failed:");
++    }
++
++    /*
++     * We set the shmid for removal immediately after attaching to it. The
++     * segment won't disappear until all processes have detached from it.
++     */
++    apc_shm_destroy(shmid);
++    return shmaddr;
++}
++
++void apc_shm_detach(void* shmaddr)
++{
++    if (shmdt(shmaddr) < 0) {
++        apc_eprint("apc_shm_detach: shmdt failed:");
++    }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_shm.h php-5.1.6/ext/APC/apc_shm.h
+--- php-5.1.6.old/ext/apc/apc_shm.h    1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_shm.h        2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,49 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.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_shm.h,v 3.6 2006/03/12 00:31:45 rasmus Exp $ */
++
++#ifndef APC_SHM_H
++#define APC_SHM_H
++
++/* Wrapper functions for unix shared memory */
++
++extern int apc_shm_create(const char* name, int proj, int size);
++extern void apc_shm_destroy(int shmid);
++extern void* apc_shm_attach(int shmid);
++extern void apc_shm_detach(void* shmaddr);
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -ruN php-5.1.6.old/ext/apc/apc_sma.c php-5.1.6/ext/APC/apc_sma.c
+--- php-5.1.6.old/ext/apc/apc_sma.c    1969-12-31 18:00:00.000000000 -0600
++++ php-5.1.6/ext/apc/apc_sma.c        2007-04-02 18:05:30.000000000 -0500
+@@ -0,0 +1,624 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <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.63 2007/04/02 09:02:57 gopalv Exp $ */
++
++#include "apc_sma.h"
++#include "apc.h"
++#include "apc_globals.h"
++#include "apc_lock.h"
++#include "apc_shm.h"
++#include <limits.h>
++#if APC_MMAP
++void *apc_mmap(char *file_mask, int size);
++void apc_unmap(void* shmaddr, int size);
++#endif
++
++/* {{{ locking macros */
++#define LOCK(c)         { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(c); }
++#define RDLOCK(c)       { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(c); }
++#define UNLOCK(c)       { apc_lck_unlock(c); HANDLE_UNBLOCK_INTERRUPTIONS(); }
++/* }}} */
++
++enum { DEFAULT_NUMSEG=1, DEFAULT_SEGSIZE=30*1024*1024 };
++
++static int sma_initialized = 0;     /* true if the sma has been initialized */
++static unsigned int sma_numseg;     /* number of shm segments to allow */
++static size_t sma_segsize;          /* size of each shm segment */
++static int* sma_segments;           /* array of shm segment ids */
++static void** sma_shmaddrs;         /* array of shm segment addresses */
++static int sma_lastseg = 0;         /* index of MRU segment */
++
++typedef struct header_t header_t;
++struct header_t {
++    apc_lck_t sma_lock;     /* segment lock, MUST BE ALIGNED for futex locks */
++    size_t segsize;         /* size of entire segment */
++    size_t avail;           /* bytes available (not necessarily contiguous) */
++    size_t nfoffset;        /* start next fit search from this offset       */
++#if ALLOC_DISTRIBUTION
++    size_t adist[30];
++#endif
++};
++
++
++/* do not enable for threaded http servers */
++/* #define __APC_SMA_DEBUG__ 1 */
++
++#ifdef __APC_SMA_DEBUG__
++/* global counter for identifying blocks 
++ * Technically it is possible to do the same
++ * using offsets, but double allocations of the
++ * same offset can happen. */
++static volatile size_t block_id = 0;
++#endif
++
++#define APC_SMA_CANARIES 1   
++
++typedef struct block_t block_t;
++struct block_t {
++    size_t size;       /* size of this block */
++    size_t next;       /* offset in segment of next free block */
++#ifdef APC_SMA_CANARIES
++    size_t canary;     /* canary to check for memory overwrites */
++#endif
++#ifdef __APC_SMA_DEBUG__
++    size_t id;         /* identifier for the memory block */ 
++#endif
++};
++
++/* The macros BLOCKAT and OFFSET are used for convenience throughout this
++ * module. Both assume the presence of a variable shmaddr that points to the
++ * beginning of the shared memory segment in question. */
++
++#define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset))
++#define OFFSET(block) ((size_t)(((char*)block) - (char*)shmaddr))
++
++/* Canary macros for setting, checking and resetting memory canaries */
++#ifdef APC_SMA_CANARIES
++    #define SET_CANARY(v) (v)->canary = 0x42424242
++    #define CHECK_CANARY(v) assert((v)->canary == 0x42424242)
++    #define RESET_CANARY(v) (v)->canary = -42
++#else
++    #define SET_CANARY(v) 
++    #define CHECK_CANARY(v)
++    #define RESET_CANARY(v)
++#endif
++
++
++#ifdef max
++#undef max
++#endif
++#define max(a, b) ((a) > (b) ? (a) : (b))
++
++/* {{{ ALIGNWORD: pad up x, aligned to the system's word boundary */
++typedef union { void* p; int i; long l; double d; void (*f)(); } apc_word_t;
++#define ALIGNWORD(x) (sizeof(apc_word_t) * (1 + (((x)-1)/sizeof(apc_word_t))))
++#define MINBLOCKSIZE (ALIGNWORD(1) + ALIGNWORD(sizeof(block_t)))