source: trunk/xcache.c @ 305

Last change on this file since 305 was 305, checked in by moo, 8 years ago

TRACE() instead of ifdef/fprintf

File size: 67.8 KB
RevLine 
[1]1
[205]2#if 0
3#define DEBUG
[236]4#endif
5
6#if 0
[230]7#define SHOW_DPRINT
[205]8#endif
[1]9
10/* {{{ macros */
11#include <stdlib.h>
12#include <stdio.h>
13#include <string.h>
14
15#include <signal.h>
16
17#include "php.h"
18#include "ext/standard/info.h"
[34]19#include "ext/standard/md5.h"
[82]20#include "ext/standard/php_math.h"
[1]21#include "zend_extensions.h"
22#include "SAPI.h"
23
24#include "xcache.h"
25#include "optimizer.h"
[27]26#include "coverager.h"
[1]27#include "disassembler.h"
28#include "align.h"
29#include "stack.h"
30#include "xcache_globals.h"
31#include "processor.h"
32#include "const_string.h"
33#include "opcode_spec.h"
[305]34#include "utils.h"
[1]35
[114]36#define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > pentry->ctime + (pentry)->ttl)
[1]37#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
38#define LOCK(x) xc_lock(x->lck)
39#define UNLOCK(x) xc_unlock(x->lck)
[130]40
41#define ENTER_LOCK_EX(x) \
[1]42    xc_lock(x->lck); \
43    zend_try { \
44        do
[130]45#define LEAVE_LOCK_EX(x) \
[1]46        while (0); \
47    } zend_catch { \
48        catched = 1; \
49    } zend_end_try(); \
[130]50    xc_unlock(x->lck)
51
52#define ENTER_LOCK(x) do { \
53    int catched = 0; \
54    ENTER_LOCK_EX(x)
55#define LEAVE_LOCK(x) \
56    LEAVE_LOCK_EX(x); \
57    if (catched) { \
58        zend_bailout(); \
59    } \
[1]60} while(0)
[130]61
[1]62/* }}} */
63
64/* {{{ globals */
[148]65static char *xc_shm_scheme = NULL;
[1]66static char *xc_mmap_path = NULL;
67static char *xc_coredump_dir = NULL;
68
69static xc_hash_t xc_php_hcache = {0};
70static xc_hash_t xc_php_hentry = {0};
71static xc_hash_t xc_var_hcache = {0};
72static xc_hash_t xc_var_hentry = {0};
73
[114]74static zend_ulong xc_php_ttl    = 0;
75static zend_ulong xc_var_maxttl = 0;
76
77enum { xc_deletes_gc_interval = 120 };
78static zend_ulong xc_php_gc_interval = 0;
79static zend_ulong xc_var_gc_interval = 0;
80
[1]81/* total size */
82static zend_ulong xc_php_size  = 0;
83static zend_ulong xc_var_size  = 0;
84
85static xc_cache_t **xc_php_caches = NULL;
86static xc_cache_t **xc_var_caches = NULL;
87
88static zend_bool xc_initized = 0;
89static zend_compile_file_t *origin_compile_file;
90
91static zend_bool xc_test = 0;
92static zend_bool xc_readonly_protection = 0;
93
[189]94zend_bool xc_have_op_array_ctor = 0;
95
[1]96static zend_bool xc_module_gotup = 0;
97static zend_bool xc_zend_extension_gotup = 0;
[278]98static zend_bool xc_zend_extension_faked = 0;
[1]99#if !COMPILE_DL_XCACHE
100#   define zend_extension_entry xcache_zend_extension_entry
101#endif
102ZEND_DLEXPORT zend_extension zend_extension_entry;
103ZEND_DECLARE_MODULE_GLOBALS(xcache);
104/* }}} */
105
106/* any function in *_dmz is only safe be called within locked(single thread) area */
107
108static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
109{
110    /* this function isn't required but can be in dmz */
111
112    if (a->type != b->type) {
113        return 0;
114    }
115    switch (a->type) {
116        case XC_TYPE_PHP:
117#ifdef HAVE_INODE
118            do {
119                xc_entry_data_php_t *ap = a->data.php;
120                xc_entry_data_php_t *bp = b->data.php;
[165]121                if (ap->inode) {
122                    return ap->inode == bp->inode
123                        && ap->device == bp->device;
124                }
[1]125            } while(0);
126#endif
127            /* fall */
128
129        case XC_TYPE_VAR:
130            do {
131#ifdef IS_UNICODE
132                if (a->name_type == IS_UNICODE) {
133                    if (a->name.ustr.len != b->name.ustr.len) {
134                        return 0;
135                    }
136                    return memcmp(a->name.ustr.val, b->name.ustr.val, (a->name.ustr.len + 1) * sizeof(UChar)) == 0;
137                }
138                else {
139                    return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
140                }
141#else
142                return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
143#endif
144
145            } while(0);
146        default:
147            assert(0);
148    }
149    return 0;
150}
151/* }}} */
[137]152static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */
[1]153{
[148]154    xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce);
[1]155}
156/* }}} */
157static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */
158{
159    xc_entry_t **head = &(xce->cache->entries[xce->hvalue]);
160    xce->next = *head;
161    *head = xce;
[32]162    xce->cache->entries_count ++;
[1]163}
164/* }}} */
165static xc_entry_t *xc_entry_store_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
166{
167    xc_entry_t *stored_xce;
168
169    xce->hits  = 0;
170    xce->ctime = XG(request_time);
171    xce->atime = XG(request_time);
172    stored_xce = xc_processor_store_xc_entry_t(xce TSRMLS_CC);
173    if (stored_xce) {
174        xc_entry_add_dmz(stored_xce);
175        return stored_xce;
176    }
177    else {
178        xce->cache->ooms ++;
179        return NULL;
180    }
181}
182/* }}} */
[137]183static void xc_entry_free_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
[114]184{
185    xce->cache->entries_count --;
186    if (xce->refcount == 0) {
[137]187        xc_entry_free_real_dmz(xce);
[114]188    }
189    else {
190        xce->next = xce->cache->deletes;
191        xce->cache->deletes = xce;
192        xce->dtime = XG(request_time);
193        xce->cache->deletes_count ++;
194    }
195    return;
196}
197/* }}} */
[1]198static void xc_entry_remove_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
199{
[114]200    xc_entry_t **pp = &(xce->cache->entries[xce->hvalue]);
[1]201    xc_entry_t *p;
[114]202    for (p = *pp; p; pp = &(p->next), p = p->next) {
[1]203        if (xc_entry_equal_dmz(xce, p)) {
[137]204            /* unlink */
205            *pp = p->next;
[138]206            xc_entry_free_dmz(xce TSRMLS_CC);
[1]207            return;
208        }
209    }
210    assert(0);
211}
212/* }}} */
213static xc_entry_t *xc_entry_find_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
214{
215    xc_entry_t *p;
216    for (p = xce->cache->entries[xce->hvalue]; p; p = p->next) {
217        if (xc_entry_equal_dmz(xce, p)) {
218            if (p->type == XC_TYPE_VAR || /* PHP */ p->data.php->mtime == xce->data.php->mtime) {
219                p->hits ++;
220                p->atime = XG(request_time);
221                return p;
222            }
223            else {
224                xc_entry_remove_dmz(p TSRMLS_CC);
225                return NULL;
226            }
227        }
228    }
229    return NULL;
230}
231/* }}} */
232static void xc_entry_hold_php_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
233{
[305]234    TRACE("hold %s", xce->name.str.val);
[1]235    xce->refcount ++;
236    xc_stack_push(&XG(php_holds)[xce->cache->cacheid], (void *)xce);
237}
238/* }}} */
239#if 0
240static void xc_entry_hold_var_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
241{
242    xce->refcount ++;
243    xc_stack_push(&XG(var_holds)[xce->cache->cacheid], (void *)xce);
244}
245/* }}} */
246#endif
247
[114]248/* helper function that loop through each entry */
249#define XC_ENTRY_APPLY_FUNC(name) int name(xc_entry_t *entry TSRMLS_DC)
250typedef XC_ENTRY_APPLY_FUNC((*cache_apply_dmz_func_t));
251static void xc_entry_apply_dmz(xc_cache_t *cache, cache_apply_dmz_func_t apply_func TSRMLS_DC) /* {{{ */
252{
253    xc_entry_t *p, **pp;
254    int i, c;
255
256    for (i = 0, c = cache->hentry->size; i < c; i ++) {
257        pp = &(cache->entries[i]);
[137]258        for (p = *pp; p; p = *pp) {
[114]259            if (apply_func(p TSRMLS_CC)) {
[137]260                /* unlink */
261                *pp = p->next;
[138]262                xc_entry_free_dmz(p TSRMLS_CC);
[114]263            }
264            else {
265                pp = &(p->next);
266            }
267        }
268    }
269}
270/* }}} */
271
272#define XC_CACHE_APPLY_FUNC(name) void name(xc_cache_t *cache TSRMLS_DC)
273/* call graph:
[120]274 * xc_gc_expires_php -> xc_gc_expires_one -> xc_entry_apply_dmz -> xc_gc_expires_php_entry_dmz
275 * xc_gc_expires_var -> xc_gc_expires_one -> xc_entry_apply_dmz -> xc_gc_expires_var_entry_dmz
[114]276 */
[120]277static XC_ENTRY_APPLY_FUNC(xc_gc_expires_php_entry_dmz) /* {{{ */
[114]278{
[305]279    TRACE("ttl %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) entry->atime, xc_php_ttl);
[114]280    if (XG(request_time) > entry->atime + xc_php_ttl) {
281        return 1;
282    }
283    return 0;
284}
285/* }}} */
[120]286static XC_ENTRY_APPLY_FUNC(xc_gc_expires_var_entry_dmz) /* {{{ */
[114]287{
288    if (VAR_ENTRY_EXPIRED(entry)) {
289        return 1;
290    }
291    return 0;
292}
293/* }}} */
294static void xc_gc_expires_one(xc_cache_t *cache, zend_ulong gc_interval, cache_apply_dmz_func_t apply_func TSRMLS_DC) /* {{{ */
295{
[305]296    TRACE("interval %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) cache->last_gc_expires, gc_interval);
[129]297    if (XG(request_time) - cache->last_gc_expires >= gc_interval) {
[114]298        ENTER_LOCK(cache) {
[129]299            if (XG(request_time) - cache->last_gc_expires >= gc_interval) {
[114]300                cache->last_gc_expires = XG(request_time);
301                xc_entry_apply_dmz(cache, apply_func TSRMLS_CC);
302            }
303        } LEAVE_LOCK(cache);
304    }
305}
306/* }}} */
[120]307static void xc_gc_expires_php(TSRMLS_D) /* {{{ */
[114]308{
309    int i, c;
310
311    if (!xc_php_ttl || !xc_php_gc_interval) {
312        return;
313    }
314
315    for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
[120]316        xc_gc_expires_one(xc_php_caches[i], xc_php_gc_interval, xc_gc_expires_php_entry_dmz TSRMLS_CC);
[114]317    }
318}
319/* }}} */
[120]320static void xc_gc_expires_var(TSRMLS_D) /* {{{ */
[114]321{
322    int i, c;
323
324    if (!xc_var_gc_interval) {
325        return;
326    }
327
328    for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
[120]329        xc_gc_expires_one(xc_var_caches[i], xc_var_gc_interval, xc_gc_expires_var_entry_dmz TSRMLS_CC);
[114]330    }
331}
332/* }}} */
333
334static XC_CACHE_APPLY_FUNC(xc_gc_delete_dmz) /* {{{ */
335{
336    xc_entry_t *p, **pp;
337
338    pp = &cache->deletes;
[141]339    for (p = *pp; p; p = *pp) {
[114]340        if (XG(request_time) - p->dtime > 3600) {
341            p->refcount = 0;
342            /* issue warning here */
343        }
344        if (p->refcount == 0) {
[137]345            /* unlink */
[114]346            *pp = p->next;
347            cache->deletes_count --;
[137]348            xc_entry_free_real_dmz(p);
[114]349        }
350        else {
351            pp = &(p->next);
352        }
353    }
354}
355/* }}} */
356static XC_CACHE_APPLY_FUNC(xc_gc_deletes_one) /* {{{ */
357{
358    if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
359        ENTER_LOCK(cache) {
360            if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
[136]361                cache->last_gc_deletes = XG(request_time);
[114]362                xc_gc_delete_dmz(cache TSRMLS_CC);
363            }
364        } LEAVE_LOCK(cache);
365    }
366}
367/* }}} */
368static void xc_gc_deletes(TSRMLS_D) /* {{{ */
369{
370    int i, c;
371
372    for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
373        xc_gc_deletes_one(xc_php_caches[i] TSRMLS_CC);
374    }
375
376    for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
377        xc_gc_deletes_one(xc_var_caches[i] TSRMLS_CC);
378    }
379}
380/* }}} */
381
[1]382/* helper functions for user functions */
[118]383static void xc_fillinfo_dmz(int cachetype, xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
[1]384{
385    zval *blocks;
386    const xc_block_t *b;
387#ifndef NDEBUG
388    xc_memsize_t avail = 0;
389#endif
390    xc_mem_t *mem = cache->mem;
[148]391    const xc_mem_handlers_t *handlers = mem->handlers;
[129]392    zend_ulong interval = (cachetype == XC_TYPE_PHP) ? xc_php_gc_interval : xc_var_gc_interval;
[1]393
394    add_assoc_long_ex(return_value, ZEND_STRS("slots"),     cache->hentry->size);
395    add_assoc_long_ex(return_value, ZEND_STRS("compiling"), cache->compiling);
396    add_assoc_long_ex(return_value, ZEND_STRS("misses"),    cache->misses);
397    add_assoc_long_ex(return_value, ZEND_STRS("hits"),      cache->hits);
398    add_assoc_long_ex(return_value, ZEND_STRS("clogs"),     cache->clogs);
399    add_assoc_long_ex(return_value, ZEND_STRS("ooms"),      cache->ooms);
400
[114]401    add_assoc_long_ex(return_value, ZEND_STRS("cached"),    cache->entries_count);
402    add_assoc_long_ex(return_value, ZEND_STRS("deleted"),   cache->deletes_count);
[118]403    if (interval) {
404        add_assoc_long_ex(return_value, ZEND_STRS("gc"),    (cache->last_gc_expires + interval) - XG(request_time));
405    }
406    else {
407        add_assoc_null_ex(return_value, ZEND_STRS("gc"));
408    }
[1]409
410    MAKE_STD_ZVAL(blocks);
411    array_init(blocks);
412
[148]413    add_assoc_long_ex(return_value, ZEND_STRS("size"),  handlers->size(mem));
414    add_assoc_long_ex(return_value, ZEND_STRS("avail"), handlers->avail(mem));
[1]415    add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection);
416
[148]417    for (b = handlers->freeblock_first(mem); b; b = handlers->freeblock_next(b)) {
[1]418        zval *bi;
419
420        MAKE_STD_ZVAL(bi);
421        array_init(bi);
422
[148]423        add_assoc_long_ex(bi, ZEND_STRS("size"),   handlers->block_size(b));
424        add_assoc_long_ex(bi, ZEND_STRS("offset"), handlers->block_offset(mem, b));
[1]425        add_next_index_zval(blocks, bi);
426#ifndef NDEBUG
[148]427        avail += handlers->block_size(b);
[1]428#endif
429    }
430    add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks);
[148]431    assert(avail == handlers->avail(mem));
[1]432}
433/* }}} */
434static void xc_fillentry_dmz(xc_entry_t *entry, int del, zval *list TSRMLS_DC) /* {{{ */
435{
436    zval* ei;
437    xc_entry_data_php_t *php;
438    xc_entry_data_var_t *var;
439
440    ALLOC_INIT_ZVAL(ei);
441    array_init(ei);
442
443    add_assoc_long_ex(ei, ZEND_STRS("size"),     entry->size);
444    add_assoc_long_ex(ei, ZEND_STRS("refcount"), entry->refcount);
445    add_assoc_long_ex(ei, ZEND_STRS("hits"),     entry->hits);
446    add_assoc_long_ex(ei, ZEND_STRS("ctime"),    entry->ctime);
447    add_assoc_long_ex(ei, ZEND_STRS("atime"),    entry->atime);
[146]448    if (del) {
449        add_assoc_long_ex(ei, ZEND_STRS("dtime"), entry->dtime);
450    }
[1]451#ifdef IS_UNICODE
452    do {
453        zval *zv;
454        ALLOC_INIT_ZVAL(zv);
455        switch (entry->name_type) {
456            case IS_UNICODE:
457                    ZVAL_UNICODEL(zv, entry->name.ustr.val, entry->name.ustr.len, 1);
458                break;
459            case IS_STRING:
460                ZVAL_STRINGL(zv, entry->name.str.val, entry->name.str.len, 1);
461                break;
462            default:
463                assert(0);
464        }
465        zv->type = entry->name_type;
466        add_assoc_zval_ex(ei, ZEND_STRS("name"), zv);
467    } while (0);
468#else
[96]469    add_assoc_stringl_ex(ei, ZEND_STRS("name"), entry->name.str.val, entry->name.str.len, 1);
[1]470#endif
471    switch (entry->type) {
472        case XC_TYPE_PHP:
473            php = entry->data.php;
[95]474            add_assoc_long_ex(ei, ZEND_STRS("sourcesize"),    php->sourcesize);
[1]475#ifdef HAVE_INODE
[95]476            add_assoc_long_ex(ei, ZEND_STRS("device"),        php->device);
477            add_assoc_long_ex(ei, ZEND_STRS("inode"),         php->inode);
[1]478#endif
[95]479            add_assoc_long_ex(ei, ZEND_STRS("mtime"),         php->mtime);
[1]480
[95]481#ifdef HAVE_XCACHE_CONSTANT
482            add_assoc_long_ex(ei, ZEND_STRS("constinfo_cnt"), php->constinfo_cnt);
483#endif
484            add_assoc_long_ex(ei, ZEND_STRS("function_cnt"),  php->funcinfo_cnt);
485            add_assoc_long_ex(ei, ZEND_STRS("class_cnt"),     php->classinfo_cnt);
[268]486#ifdef ZEND_ENGINE_2_1
487            add_assoc_long_ex(ei, ZEND_STRS("autoglobal_cnt"),php->autoglobal_cnt);
488#endif
[1]489            break;
490        case XC_TYPE_VAR:
491            var = entry->data.var;
492            break;
493
494        default:
495            assert(0);
496    }
497
498    add_next_index_zval(list, ei);
499}
500/* }}} */
501static void xc_filllist_dmz(xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
502{
503    zval* list;
504    int i, c;
505    xc_entry_t *e;
506
507    ALLOC_INIT_ZVAL(list);
508    array_init(list);
509
510    for (i = 0, c = cache->hentry->size; i < c; i ++) {
511        for (e = cache->entries[i]; e; e = e->next) {
[11]512            xc_fillentry_dmz(e, 0, list TSRMLS_CC);
[1]513        }
514    }
515    add_assoc_zval(return_value, "cache_list", list);
516
517    ALLOC_INIT_ZVAL(list);
518    array_init(list);
519    for (e = cache->deletes; e; e = e->next) {
[11]520        xc_fillentry_dmz(e, 1, list TSRMLS_CC);
[1]521    }
522    add_assoc_zval(return_value, "deleted_list", list);
523}
524/* }}} */
525
526static zend_op_array *xc_entry_install(xc_entry_t *xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
527{
528    zend_uint i;
529    xc_entry_data_php_t *p = xce->data.php;
530#ifndef ZEND_ENGINE_2
531    /* new ptr which is stored inside CG(class_table) */
532    xc_cest_t **new_cest_ptrs = (xc_cest_t **)do_alloca(sizeof(xc_cest_t*) * p->classinfo_cnt);
533#endif
534
[212]535    CG(active_op_array) = p->op_array;
536
[95]537#ifdef HAVE_XCACHE_CONSTANT
538    /* install constant */
539    for (i = 0; i < p->constinfo_cnt; i ++) {
540        xc_constinfo_t *ci = &p->constinfos[i];
541        xc_install_constant(xce->name.str.val, &ci->constant,
542                UNISW(0, ci->type), ci->key, ci->key_size TSRMLS_CC);
543    }
544#endif
545
[1]546    /* install function */
547    for (i = 0; i < p->funcinfo_cnt; i ++) {
548        xc_funcinfo_t  *fi = &p->funcinfos[i];
549        xc_install_function(xce->name.str.val, &fi->func,
550                UNISW(0, fi->type), fi->key, fi->key_size TSRMLS_CC);
551    }
552
553    /* install class */
554    for (i = 0; i < p->classinfo_cnt; i ++) {
555        xc_classinfo_t *ci = &p->classinfos[i];
556#ifndef ZEND_ENGINE_2
557        zend_class_entry *ce = CestToCePtr(ci->cest);
558        /* fix pointer to the be which inside class_table */
559        if (ce->parent) {
[224]560            zend_uint class_idx = (/* class_num */ (int) (long) ce->parent) - 1;
[1]561            assert(class_idx < i);
562            ci->cest.parent = new_cest_ptrs[class_idx];
563        }
564        new_cest_ptrs[i] =
565#endif
[212]566        xc_install_class(xce->name.str.val, &ci->cest, ci->oplineno,
[1]567                UNISW(0, ci->type), ci->key, ci->key_size TSRMLS_CC);
568    }
569
[268]570#ifdef ZEND_ENGINE_2_1
571    /* trigger auto_globals jit */
572    for (i = 0; i < p->autoglobal_cnt; i ++) {
573        xc_autoglobal_t *aginfo = &p->autoglobals[i];
574        /*
575        zend_auto_global *auto_global;
576        if (zend_u_hash_find(CG(auto_globals), aginfo->type, aginfo->key, aginfo->key_len+1, (void **) &auto_global)==SUCCESS) {
577            if (auto_global->armed) {
578                auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC);
579            }
580        }
581        */
582        zend_u_is_auto_global(aginfo->type, aginfo->key, aginfo->key_len TSRMLS_CC);
583    }
584#endif
585
[1]586    i = 1;
587    zend_hash_add(&EG(included_files), xce->name.str.val, xce->name.str.len+1, (void *)&i, sizeof(int), NULL);
[131]588    if (h) {
589        zend_llist_add_element(&CG(open_files), h);
590    }
[1]591
592#ifndef ZEND_ENGINE_2
593    free_alloca(new_cest_ptrs);
594#endif
595    return p->op_array;
596}
597/* }}} */
598
[11]599static inline void xc_entry_unholds_real(xc_stack_t *holds, xc_cache_t **caches, int cachecount TSRMLS_DC) /* {{{ */
[1]600{
601    int i;
602    xc_stack_t *s;
603    xc_cache_t *cache;
604    xc_entry_t *xce;
605
606    for (i = 0; i < cachecount; i ++) {
607        s = &holds[i];
[305]608        TRACE("holded %d", xc_stack_size(s));
[1]609        if (xc_stack_size(s)) {
610            cache = ((xc_entry_t *)xc_stack_top(s))->cache;
611            ENTER_LOCK(cache) {
[140]612                while (xc_stack_size(s)) {
613                    xce = (xc_entry_t*) xc_stack_pop(s);
[305]614                    TRACE("unhold %s", xce->name.str.val);
[1]615                    xce->refcount --;
616                    assert(xce->refcount >= 0);
617                }
618            } LEAVE_LOCK(cache);
619        }
620    }
621}
622/* }}} */
623static void xc_entry_unholds(TSRMLS_D) /* {{{ */
624{
[11]625    xc_entry_unholds_real(XG(php_holds), xc_php_caches, xc_php_hcache.size TSRMLS_CC);
626    xc_entry_unholds_real(XG(var_holds), xc_var_caches, xc_var_hcache.size TSRMLS_CC);
[1]627}
628/* }}} */
[11]629static int xc_stat(const char *filename, const char *include_path, struct stat *pbuf TSRMLS_DC) /* {{{ */
[1]630{
[165]631    char filepath[MAXPATHLEN];
[1]632    char *paths, *path;
633    char *tokbuf;
634    int size = strlen(include_path) + 1;
635    char tokens[] = { DEFAULT_DIR_SEPARATOR, '\0' };
636
637    paths = (char *)do_alloca(size);
638    memcpy(paths, include_path, size);
639
[11]640    for (path = php_strtok_r(paths, tokens, &tokbuf); path; path = php_strtok_r(NULL, tokens, &tokbuf)) {
[165]641        if (snprintf(filepath, sizeof(filepath), "%s/%s", path, filename) >= MAXPATHLEN - 1) {
[1]642            continue;
643        }
644        if (VCWD_STAT(filepath, pbuf) == 0) {
645            free_alloca(paths);
646            return 0;
647        }
648    }
649
650    free_alloca(paths);
651
652    return 1;
653}
654/* }}} */
655
656#define HASH(i) (i)
657#define HASH_USTR_L(t, s, l) HASH(zend_u_inline_hash_func(t, s, (l + 1) * sizeof(UChar)))
658#define HASH_STR_L(s, l) HASH(zend_inline_hash_func(s, l + 1))
659#define HASH_STR(s) HASH_STR_L(s, strlen(s) + 1)
660#define HASH_NUM(n) HASH(n)
[165]661static inline xc_hash_value_t xc_entry_hash_name(xc_entry_t *xce TSRMLS_DC) /* {{{ */
[1]662{
[103]663    return UNISW(NOTHING, UG(unicode) ? HASH_USTR_L(xce->name_type, xce->name.uni.val, xce->name.uni.len) :)
[1]664        HASH_STR_L(xce->name.str.val, xce->name.str.len);
665}
666/* }}} */
[165]667#define xc_entry_hash_var xc_entry_hash_name
[152]668static inline xc_hash_value_t xc_entry_hash_php(xc_entry_t *xce TSRMLS_DC) /* {{{ */
[1]669{
670#ifdef HAVE_INODE
[165]671    if (xce->data.php->inode) {
672        return HASH(xce->data.php->device + xce->data.php->inode);
673    }
[1]674#endif
[165]675    return xc_entry_hash_name(xce TSRMLS_CC);
[1]676}
677/* }}} */
[165]678static int xc_entry_init_key_php(xc_entry_t *xce, char *filename, char *opened_path_buffer TSRMLS_DC) /* {{{ */
[1]679{
680    struct stat buf, *pbuf;
681    xc_hash_value_t hv;
682    int cacheid;
683    xc_entry_data_php_t *php;
[75]684    char *ptr;
[1]685
686    if (!filename || !SG(request_info).path_translated) {
687        return 0;
688    }
689
[165]690    php = xce->data.php;
691
692    if (XG(stat)) {
[1]693        if (strcmp(SG(request_info).path_translated, filename) == 0) {
694            /* sapi has already done this stat() for us */
695            pbuf = sapi_get_stat(TSRMLS_C);
696            if (pbuf) {
[165]697                goto stat_done;
[1]698            }
699        }
700
[75]701        /* absolute path */
[1]702        pbuf = &buf;
703        if (IS_ABSOLUTE_PATH(filename, strlen(filename))) {
704            if (VCWD_STAT(filename, pbuf) != 0) {
705                return 0;
706            }
[165]707            goto stat_done;
[1]708        }
[75]709
710        /* relative path */
711        if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) {
712            ptr = filename + 1;
713            if (*ptr == '.') {
714                while (*(++ptr) == '.');
715                if (!IS_SLASH(*ptr)) {
716                    goto not_relative_path;
717                }   
718            }
719
720            if (VCWD_STAT(filename, pbuf) != 0) {
[1]721                return 0;
722            }
[165]723            goto stat_done;
[1]724        }
[75]725not_relative_path:
726
727        /* use include_path */
728        if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != 0) {   
729            return 0;
730        }
[1]731
[165]732        /* fall */
733
734stat_done:
[202]735        if (XG(request_time) - pbuf->st_mtime < 2 && !xc_test) {
[165]736            return 0;
737        }
738
739        php->mtime        = pbuf->st_mtime;
740#ifdef HAVE_INODE
741        php->device       = pbuf->st_dev;
742        php->inode        = pbuf->st_ino;
743#endif
744        php->sourcesize   = pbuf->st_size;
[1]745    }
[165]746    else { /* XG(inode) */
747        php->mtime        = 0;
748#ifdef HAVE_INODE
749        php->device       = 0;
750        php->inode        = 0;
751#endif
752        php->sourcesize   = 0;
753    }
[1]754
[165]755#ifdef HAVE_INODE
756    if (!php->inode)
757#endif
758    {
759        /* hash on filename, let's expand it to real path */
760        filename = expand_filepath(filename, opened_path_buffer TSRMLS_CC);
761        if (filename == NULL) {
762            return 0;
763        }
764    }
765
[19]766    UNISW(NOTHING, xce->name_type = IS_STRING;)
[1]767    xce->name.str.val = filename;
768    xce->name.str.len = strlen(filename);
769
[152]770    hv = xc_entry_hash_php(xce TSRMLS_CC);
[1]771    cacheid = (hv & xc_php_hcache.mask);
772    xce->cache = xc_php_caches[cacheid];
773    hv >>= xc_php_hcache.bits;
774    xce->hvalue = (hv & xc_php_hentry.mask);
775
776    xce->type = XC_TYPE_PHP;
777    return 1;
778}
779/* }}} */
[212]780static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
781{
782    char *class_name;
783    int i, class_len;
784    xc_cest_t cest;
785    xc_entry_data_php_t *php = (xc_entry_data_php_t *) data;
786
787    class_name = opline->op1.u.constant.value.str.val;
788    class_len  = opline->op1.u.constant.value.str.len;
789    if (zend_hash_find(CG(class_table), class_name, class_len, (void **) &cest) == FAILURE) {
790        assert(0);
791    }
[305]792    TRACE("got ZEND_DECLARE_INHERITED_CLASS: %s", class_name + 1);
[212]793    /* let's see which class */
794    for (i = 0; i < php->classinfo_cnt; i ++) {
795        if (memcmp(ZSTR_S(php->classinfos[i].key), class_name, class_len) == 0) {
796            php->classinfos[i].oplineno = oplineno;
797            php->have_early_binding = 1;
798            break;
799        }
800    }
801
802    if (i == php->classinfo_cnt) {
803        assert(0);
804    }
805}
806/* }}} */
[1]807static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
808{
809    xc_sandbox_t sandbox;
810    zend_op_array *op_array;
811    xc_entry_t xce, *stored_xce;
812    xc_entry_data_php_t php;
813    xc_cache_t *cache;
814    zend_bool clogged = 0;
815    zend_bool catched = 0;
816    char *filename;
[165]817    char opened_path_buffer[MAXPATHLEN];
[95]818    int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
[212]819    int i;
[1]820
821    if (!xc_initized) {
822        assert(0);
823    }
824
825    if (!XG(cacher)) {
826        op_array = origin_compile_file(h, type TSRMLS_CC);
827#ifdef HAVE_XCACHE_OPTIMIZER
828        if (XG(optimizer)) {
829            xc_optimize(op_array TSRMLS_CC);
830        }
831#endif
832        return op_array;
833    }
834
835    /* {{{ prepare key
836     * include_once() and require_once() gives us opened_path
837     * however, include() and require() non-absolute path which break
838     * included_files, and may confuse with (include|require)_once
839     * -- Xuefer
840     */
841
842    filename = h->opened_path ? h->opened_path : h->filename;
843    xce.data.php = &php;
[165]844    if (!xc_entry_init_key_php(&xce, filename, opened_path_buffer TSRMLS_CC)) {
[1]845        return origin_compile_file(h, type TSRMLS_CC);
846    }
847    cache = xce.cache;
848    /* }}} */
849    /* {{{ restore */
850    /* stale precheck */
851    if (cache->compiling) {
852        cache->clogs ++; /* is it safe here? */
853        return origin_compile_file(h, type TSRMLS_CC);
854    }
855
856    stored_xce = NULL;
857    op_array = NULL;
[130]858    ENTER_LOCK_EX(cache) {
[1]859        /* clogged */
860        if (cache->compiling) {
861            cache->clogs ++;
862            op_array = NULL;
863            clogged = 1;
864            break;
865        }
866
867        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
868        /* found */
869        if (stored_xce) {
[305]870            TRACE("found %s, catch it", stored_xce->name.str.val);
[1]871            xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
872            cache->hits ++;
873            break;
874        }
875
876        cache->compiling = XG(request_time);
877        cache->misses ++;
[130]878    } LEAVE_LOCK_EX(cache);
[1]879
[130]880    if (catched) {
881        cache->compiling = 0;
882        zend_bailout();
883    }
884
[1]885    /* found */
886    if (stored_xce) {
887        goto restore;
888    }
889
890    /* clogged */
891    if (clogged) {
892        return origin_compile_file(h, type TSRMLS_CC);
893    }
894    /* }}} */
895
896    /* {{{ compile */
[305]897    TRACE("compiling %s", filename);
[1]898
899    /* make compile inside sandbox */
900    xc_sandbox_init(&sandbox, filename TSRMLS_CC);
901
[95]902    old_classinfo_cnt = zend_hash_num_elements(CG(class_table));
903    old_funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
904    old_constinfo_cnt  = zend_hash_num_elements(EG(zend_constants));
905
[1]906    zend_try {
907        op_array = origin_compile_file(h, type TSRMLS_CC);
908    } zend_catch {
909        catched = 1;
910    } zend_end_try();
911
912    if (catched) {
913        goto err_bailout;
914    }
915
916    if (op_array == NULL) {
917        goto err_oparray;
918    }
919
[86]920    filename = h->opened_path ? h->opened_path : h->filename;
[165]921    /* none-inode enabled entry hash/compare on name
922     * do not update to its name to real pathname
923     */
924#ifdef HAVE_INODE
925    if (xce.data.php->inode)
926    {
927        if (xce.name.str.val != filename) {
928            xce.name.str.val = filename;
929            xce.name.str.len = strlen(filename);
930        }
[86]931    }
[212]932#endif
[86]933
[1]934#ifdef HAVE_XCACHE_OPTIMIZER
935    if (XG(optimizer)) {
936        xc_optimize(op_array TSRMLS_CC);
937    }
938#endif
[212]939    /* }}} */
940    /* {{{ prepare */
[1]941    php.op_array      = op_array;
942
[95]943#ifdef HAVE_XCACHE_CONSTANT
[268]944    php.constinfo_cnt  = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
[95]945#endif
[268]946    php.funcinfo_cnt   = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
947    php.classinfo_cnt  = zend_hash_num_elements(CG(class_table))    - old_classinfo_cnt;
948#ifdef ZEND_ENGINE_2_1
949    /* {{{ count php.autoglobal_cnt */ {
950        Bucket *b;
[1]951
[268]952        php.autoglobal_cnt = 0;
953        for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
954            zend_auto_global *auto_global = (zend_auto_global *) b->pData;
955            /* check if actived */
956            if (auto_global->auto_global_callback && !auto_global->armed) {
957                php.autoglobal_cnt ++;
958            }
959        }
960    }
961    /* }}} */
962#endif
963
[95]964#define X_ALLOC_N(var, cnt) do {     \
965    if (php.cnt) {                   \
966        ECALLOC_N(php.var, php.cnt); \
967        if (!php.var) {              \
968            goto err_##var;          \
969        }                            \
970    }                                \
971    else {                           \
972        php.var = NULL;              \
973    }                                \
974} while (0)
975
976#ifdef HAVE_XCACHE_CONSTANT
[268]977    X_ALLOC_N(constinfos,  constinfo_cnt);
[95]978#endif
[268]979    X_ALLOC_N(funcinfos,   funcinfo_cnt);
980    X_ALLOC_N(classinfos,  classinfo_cnt);
981#ifdef ZEND_ENGINE_2_1
982    X_ALLOC_N(autoglobals, autoglobal_cnt);
983#endif
[95]984#undef X_ALLOC
[1]985    /* }}} */
986    /* {{{ shallow copy, pointers only */ {
987        Bucket *b;
988        unsigned int i;
989
[95]990#define COPY_H(vartype, var, cnt, name, datatype) do {        \
991    for (i = 0; b; i ++, b = b->pListNext) {                  \
992        vartype *data = &php.var[i];                          \
993                                                              \
994        if (i < old_##cnt) {                                  \
995            continue;                                         \
996        }                                                     \
997                                                              \
998        assert(i < old_##cnt + php.cnt);                      \
999        assert(b->pData);                                     \
1000        memcpy(&data->name, b->pData, sizeof(datatype));      \
1001        UNISW(NOTHING, data->type = b->key.type;)             \
[103]1002        if (UNISW(1, b->key.type == IS_STRING)) {             \
[200]1003            ZSTR_S(data->key)      = BUCKET_KEY_S(b);          \
[103]1004        }                                                     \
1005        else {                                                \
[200]1006            ZSTR_U(data->key)      = BUCKET_KEY_U(b);         \
[103]1007        }                                                     \
[95]1008        data->key_size   = b->nKeyLength;                     \
1009    }                                                         \
1010} while(0)
[1]1011
[95]1012#ifdef HAVE_XCACHE_CONSTANT
1013        b = EG(zend_constants)->pListHead; COPY_H(xc_constinfo_t, constinfos, constinfo_cnt, constant, zend_constant);
1014#endif
1015        b = CG(function_table)->pListHead; COPY_H(xc_funcinfo_t,  funcinfos,  funcinfo_cnt,  func,     zend_function);
1016        b = CG(class_table)->pListHead;    COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest,     xc_cest_t);
[1]1017
[95]1018#undef COPY_H
[268]1019
1020        /* for ZE1, cest need to be fixed inside store */
1021
1022#ifdef ZEND_ENGINE_2_1
1023        /* scan for acatived auto globals */
1024        i = 0;
1025        for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
1026            zend_auto_global *auto_global = (zend_auto_global *) b->pData;
1027            /* check if actived */
1028            if (auto_global->auto_global_callback && !auto_global->armed) {
[299]1029                xc_autoglobal_t *data = &php.autoglobals[i];
[268]1030
1031                assert(i < php.autoglobal_cnt);
[299]1032                i ++;
[268]1033                UNISW(NOTHING, data->type = b->key.type;)
1034                if (UNISW(1, b->key.type == IS_STRING)) {
1035                    ZSTR_S(data->key)     = BUCKET_KEY_S(b);
1036                }
1037                else {
1038                    ZSTR_U(data->key)     = BUCKET_KEY_U(b);
1039                }
1040                data->key_len = b->nKeyLength - 1;
1041            }
1042        }
1043#endif
[1]1044    }
1045    /* }}} */
[212]1046    /* {{{ find inherited classes that should be early-binding */
1047    php.have_early_binding = 0;
1048    for (i = 0; i < php.classinfo_cnt; i ++) {
1049        php.classinfos[i].oplineno = -1;
1050    }
1051
1052    xc_undo_pass_two(php.op_array TSRMLS_CC);
1053    xc_foreach_early_binding_class(php.op_array, xc_cache_early_binding_class_cb, (void *) &php TSRMLS_CC);
1054    xc_redo_pass_two(php.op_array TSRMLS_CC);
1055    /* }}} */
[230]1056#ifdef SHOW_DPRINT
1057    xc_dprint(&xce, 0 TSRMLS_CC);
1058#endif
[130]1059    ENTER_LOCK_EX(cache) { /* {{{ store/add entry */
[1]1060        stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
[130]1061    } LEAVE_LOCK_EX(cache);
[1]1062    /* }}} */
[305]1063    TRACE("%s", "stored");
[1]1064
[95]1065#define X_FREE(var) \
1066    if (xce.data.php->var) { \
1067        efree(xce.data.php->var); \
1068    } \
1069err_##var:
1070
[268]1071#ifdef ZEND_ENGINE_2_1
1072    X_FREE(autoglobals)
1073#endif
[95]1074    X_FREE(classinfos)
1075    X_FREE(funcinfos)
1076#ifdef HAVE_XCACHE_CONSTANT
1077    X_FREE(constinfos)
1078#endif
1079#undef X_FREE
1080
[1]1081err_oparray:
1082err_bailout:
1083
1084    if (xc_test && stored_xce) {
[131]1085        /* free it, no install. restore now */
[1]1086        xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
1087    }
[216]1088    else if (!op_array) {
1089        /* failed to compile free it, no install */
1090        xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
1091    }
[1]1092    else {
[212]1093        CG(active_op_array) = op_array;
[1]1094        xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
1095    }
1096
1097    ENTER_LOCK(cache) {
1098        cache->compiling = 0;
1099    } LEAVE_LOCK(cache);
1100    if (catched) {
1101        zend_bailout();
1102    }
1103    if (xc_test && stored_xce) {
[132]1104#ifdef ZEND_ENGINE_2
[119]1105        destroy_op_array(op_array TSRMLS_CC);
[132]1106#else
1107        destroy_op_array(op_array);
1108#endif
[119]1109        efree(op_array);
[131]1110        h = NULL;
[1]1111        goto restore;
1112    }
1113    return op_array;
1114
1115restore:
[235]1116    CG(in_compilation)    = 1;
1117    CG(compiled_filename) = stored_xce->name.str.val;
1118    CG(zend_lineno)       = 0;
[305]1119    TRACE("restoring %s", stored_xce->name.str.val);
[1]1120    xc_processor_restore_xc_entry_t(&xce, stored_xce, xc_readonly_protection TSRMLS_CC);
[230]1121#ifdef SHOW_DPRINT
1122    xc_dprint(&xce, 0 TSRMLS_CC);
1123#endif
[1]1124
[95]1125    catched = 0;
1126    zend_try {
1127        op_array = xc_entry_install(&xce, h TSRMLS_CC);
1128    } zend_catch {
1129        catched = 1;
1130    } zend_end_try();
1131
1132#define X_FREE(var) \
1133    if (xce.data.php->var) { \
1134        efree(xce.data.php->var); \
1135    }
[268]1136#ifdef ZEND_ENGINE_2_1
1137    X_FREE(autoglobals)
1138#endif
[95]1139    X_FREE(classinfos)
1140    X_FREE(funcinfos)
1141#ifdef HAVE_XCACHE_CONSTANT
1142    X_FREE(constinfos)
1143#endif
1144#undef X_FREE
[1]1145    efree(xce.data.php);
[95]1146
1147    if (catched) {
1148        zend_bailout();
1149    }
[235]1150    CG(in_compilation)    = 0;
1151    CG(compiled_filename) = NULL;
[305]1152    TRACE("restored  %s", stored_xce->name.str.val);
[1]1153    return op_array;
1154}
1155/* }}} */
1156
1157/* gdb helper functions, but N/A for coredump */
1158int xc_is_rw(const void *p) /* {{{ */
1159{
[148]1160    xc_shm_t *shm;
[1]1161    int i;
1162    if (!xc_initized) {
1163        return 0;
1164    }
1165    for (i = 0; i < xc_php_hcache.size; i ++) {
[148]1166        shm = xc_php_caches[i]->shm;
1167        if (shm->handlers->is_readwrite(shm, p)) {
[1]1168            return 1;
1169        }
1170    }
1171    for (i = 0; i < xc_var_hcache.size; i ++) {
[148]1172        shm = xc_var_caches[i]->shm;
1173        if (shm->handlers->is_readwrite(shm, p)) {
[1]1174            return 1;
1175        }
1176    }
1177    return 0;
1178}
1179/* }}} */
1180int xc_is_ro(const void *p) /* {{{ */
1181{
[148]1182    xc_shm_t *shm;
[1]1183    int i;
1184    if (!xc_initized) {
1185        return 0;
1186    }
1187    for (i = 0; i < xc_php_hcache.size; i ++) {
[148]1188        shm = xc_php_caches[i]->shm;
1189        if (shm->handlers->is_readonly(shm, p)) {
[1]1190            return 1;
1191        }
1192    }
1193    for (i = 0; i < xc_var_hcache.size; i ++) {
[148]1194        shm = xc_var_caches[i]->shm;
1195        if (shm->handlers->is_readonly(shm, p)) {
[1]1196            return 1;
1197        }
1198    }
1199    return 0;
1200}
1201/* }}} */
1202int xc_is_shm(const void *p) /* {{{ */
1203{
1204    return xc_is_ro(p) || xc_is_rw(p);
1205}
1206/* }}} */
1207
1208/* module helper function */
1209static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
1210{
[11]1211    typedef struct {
[1]1212        const char *prefix;
[20]1213        zend_uchar (*getsize)();
[1]1214        const char *(*get)(zend_uchar i);
[11]1215    } xc_meminfo_t;
1216    xc_meminfo_t nameinfos[] = {
[1]1217        { "",        xc_get_op_type_count,   xc_get_op_type   },
1218        { "",        xc_get_data_type_count, xc_get_data_type },
1219        { "",        xc_get_opcode_count,    xc_get_opcode    },
1220        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
1221        { NULL, NULL, NULL }
1222    };
[11]1223    xc_meminfo_t* p;
[20]1224    zend_uchar i, count;
[1]1225    char const_name[96];
1226    int const_name_len;
1227    int undefdone = 0;
1228
1229    for (p = nameinfos; p->getsize; p ++) {
[20]1230        count = p->getsize();
1231        for (i = 0; i < count; i ++) {
[1]1232            const char *name = p->get(i);
1233            if (!name) continue;
1234            if (strcmp(name, "UNDEF") == 0) {
1235                if (undefdone) continue;
1236                undefdone = 1;
1237            }
1238            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
1239            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1240        }
1241    }
1242
1243    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1244    zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1245    zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
[119]1246    zend_register_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1247    zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
[1]1248    return 0;
1249}
1250/* }}} */
[11]1251static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
[1]1252{
1253    int i;
1254    xc_cache_t *cache;
1255    xc_shm_t *shm;
1256
1257    if (!caches) {
1258        return NULL;
1259    }
1260    shm = NULL;
1261    for (i = 0; i < hcache->size; i ++) {
1262        cache = caches[i];
1263        if (cache) {
1264            if (cache->lck) {
1265                xc_lock_destroy(cache->lck);
1266            }
1267            /* do NOT free
1268            if (cache->entries) {
[148]1269                cache->mem->handlers->free(cache->mem, cache->entries);
[1]1270            }
[148]1271            cache->mem->handlers->free(cache->mem, cache);
[1]1272            */
[154]1273            shm = cache->shm;
[148]1274            shm->handlers->memdestroy(cache->mem);
[1]1275        }
1276    }
1277    free(caches);
1278    return shm;
1279}
1280/* }}} */
[148]1281static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */
[1]1282{
1283    xc_cache_t **caches = NULL, *cache;
1284    xc_mem_t *mem;
[114]1285    time_t now = time(NULL);
[1]1286    int i;
[49]1287    xc_memsize_t memsize;
[11]1288
[49]1289    memsize = shmsize / hcache->size;
[1]1290
[49]1291    /* Don't let it break out of mem after ALIGNed
1292     * This is important for
1293     * Simply loop until it fit our need
1294     */
1295    while (ALIGN(memsize) * hcache->size > shmsize && ALIGN(memsize) != memsize) {
1296        if (memsize < ALIGN(1)) {
1297            CHECK(NULL, "cache too small");
1298        }
1299        memsize --;
1300    }
1301
[1]1302    CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
1303
1304    for (i = 0; i < hcache->size; i ++) {
[148]1305        CHECK(mem            = shm->handlers->meminit(shm, memsize), "Failed init memory allocator");
1306        CHECK(cache          = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
1307        CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
[1]1308        CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
1309
1310        cache->hcache  = hcache;
1311        cache->hentry  = hentry;
1312        cache->shm     = shm;
1313        cache->mem     = mem;
1314        cache->cacheid = i;
[114]1315        cache->last_gc_deletes = now;
1316        cache->last_gc_expires = now;
[1]1317        caches[i] = cache;
1318    }
1319    return caches;
1320
1321err:
1322    if (caches) {
1323        xc_cache_destroy(caches, hcache);
1324    }
1325    return NULL;
1326}
1327/* }}} */
1328static void xc_destroy() /* {{{ */
1329{
1330    xc_shm_t *shm = NULL;
1331
1332    if (origin_compile_file) {
1333        zend_compile_file = origin_compile_file;
1334        origin_compile_file = NULL;
1335    }
1336
1337    if (xc_php_caches) {
1338        shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
1339        xc_php_caches = NULL;
1340    }
1341    if (xc_var_caches) {
1342        shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
1343        xc_var_caches = NULL;
1344    }
1345    if (shm) {
1346        xc_shm_destroy(shm);
1347    }
1348}
1349/* }}} */
1350static int xc_init(int module_number TSRMLS_DC) /* {{{ */
1351{
1352    xc_shm_t *shm;
1353
[11]1354    xc_php_caches = xc_var_caches = NULL;
1355
[1]1356    if (xc_php_size || xc_var_size) {
[148]1357        CHECK(shm = xc_shm_init(xc_shm_scheme, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection, xc_mmap_path, NULL), "Cannot create shm");
1358        if (!shm->handlers->can_readonly(shm)) {
[1]1359            xc_readonly_protection = 0;
1360        }
1361
1362        if (xc_php_size) {
1363            origin_compile_file = zend_compile_file;
1364            zend_compile_file = xc_compile_file;
1365
[148]1366            CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
[1]1367        }
1368
1369        if (xc_var_size) {
[148]1370            CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache");
[1]1371        }
1372    }
1373    return 1;
1374
1375err:
1376    if (xc_php_caches || xc_var_caches) {
1377        xc_destroy();
1378        /* shm destroied */
1379    }
1380    else if (shm) {
1381        xc_shm_destroy(shm);
1382    }
1383    return 0;
1384}
1385/* }}} */
1386static void xc_request_init(TSRMLS_D) /* {{{ */
1387{
[17]1388    int i;
1389
1390    if (xc_php_hcache.size && !XG(php_holds)) {
1391        XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
1392        for (i = 0; i < xc_php_hcache.size; i ++) {
1393            xc_stack_init(&XG(php_holds[i]));
1394        }
1395    }
1396
1397    if (xc_var_hcache.size && !XG(var_holds)) {
1398        XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
1399        for (i = 0; i < xc_var_hcache.size; i ++) {
1400            xc_stack_init(&XG(var_holds[i]));
1401        }
1402    }
1403
[1]1404    if (XG(cacher)) {
1405#if PHP_API_VERSION <= 20041225
1406        XG(request_time) = time(NULL);
1407#else
1408        XG(request_time) = sapi_get_request_time(TSRMLS_C);
1409#endif
1410    }
[27]1411#ifdef HAVE_XCACHE_COVERAGER
1412    xc_coverager_request_init(TSRMLS_C);
[1]1413#endif
1414}
1415/* }}} */
1416static void xc_request_shutdown(TSRMLS_D) /* {{{ */
1417{
1418    xc_entry_unholds(TSRMLS_C);
[120]1419    xc_gc_expires_php(TSRMLS_C);
1420    xc_gc_expires_var(TSRMLS_C);
[114]1421    xc_gc_deletes(TSRMLS_C);
[27]1422#ifdef HAVE_XCACHE_COVERAGER
1423    xc_coverager_request_shutdown(TSRMLS_C);
[1]1424#endif
1425}
1426/* }}} */
[92]1427/* {{{ PHP_GINIT_FUNCTION(xcache) */
1428static
1429#ifdef PHP_GINIT_FUNCTION
1430PHP_GINIT_FUNCTION(xcache)
1431#else
1432void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
1433#endif
[1]1434{
[92]1435    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
[1]1436}
1437/* }}} */
[92]1438/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
1439static
1440#ifdef PHP_GSHUTDOWN_FUNCTION
1441PHP_GSHUTDOWN_FUNCTION(xcache)
1442#else
1443void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
1444#endif
[1]1445{
1446    int i;
1447
[92]1448    if (xcache_globals->php_holds != NULL) {
[1]1449        for (i = 0; i < xc_php_hcache.size; i ++) {
[92]1450            xc_stack_destroy(&xcache_globals->php_holds[i]);
[1]1451        }
[92]1452        free(xcache_globals->php_holds);
1453        xcache_globals->php_holds = NULL;
[1]1454    }
1455
[92]1456    if (xcache_globals->var_holds != NULL) {
[1]1457        for (i = 0; i < xc_var_hcache.size; i ++) {
[92]1458            xc_stack_destroy(&xcache_globals->var_holds[i]);
[1]1459        }
[92]1460        free(xcache_globals->var_holds);
1461        xcache_globals->var_holds = NULL;
[1]1462    }
1463}
1464/* }}} */
1465
1466/* user functions */
[55]1467static int xcache_admin_auth_check(TSRMLS_D) /* {{{ */
[34]1468{
1469    zval **server = NULL;
1470    zval **user = NULL;
1471    zval **pass = NULL;
1472    char *admin_user = NULL;
1473    char *admin_pass = NULL;
1474    HashTable *ht;
1475
1476    if (cfg_get_string("xcache.admin.user", &admin_user) == FAILURE || !admin_user[0]) {
1477        admin_user = NULL;
1478    }
1479    if (cfg_get_string("xcache.admin.pass", &admin_pass) == FAILURE || !admin_pass[0]) {
1480        admin_pass = NULL;
1481    }
1482
1483    if (admin_user == NULL || admin_pass == NULL) {
1484        php_error_docref(NULL TSRMLS_CC, E_ERROR, "xcache.admin.user and xcache.admin.pass is required");
1485        zend_bailout();
1486    }
1487    if (strlen(admin_pass) != 32) {
1488        php_error_docref(NULL TSRMLS_CC, E_ERROR, "unexpect %d bytes of xcache.admin.pass, expected 32 bytes, the password after md5()", strlen(admin_pass));
1489        zend_bailout();
1490    }
1491
[105]1492#ifdef ZEND_ENGINE_2_1
[113]1493    zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
[105]1494#endif
[34]1495    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != SUCCESS || Z_TYPE_PP(server) != IS_ARRAY) {
1496        php_error_docref(NULL TSRMLS_CC, E_ERROR, "_SERVER is corrupted");
1497        zend_bailout();
1498    }
1499    ht = HASH_OF((*server));
1500
1501    if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
1502        user = NULL;
1503    }
1504    else if (Z_TYPE_PP(user) != IS_STRING) {
1505        user = NULL;
1506    }
1507
1508    if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {
1509        pass = NULL;
1510    }
1511    else if (Z_TYPE_PP(pass) != IS_STRING) {
1512        pass = NULL;
1513    }
1514
1515    if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {
1516        PHP_MD5_CTX context;
1517        char md5str[33];
1518        unsigned char digest[16];
1519
1520        PHP_MD5Init(&context);
[91]1521        PHP_MD5Update(&context, (unsigned char *) Z_STRVAL_PP(pass), Z_STRLEN_PP(pass));
[34]1522        PHP_MD5Final(digest, &context);
1523
1524        md5str[0] = '\0';
1525        make_digest(md5str, digest);
1526        if (strcmp(admin_pass, md5str) == 0) {
1527            return 1;
1528        }
1529    }
1530
1531#define STR "WWW-authenticate: basic realm='XCache Administration'"
1532    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1533#undef STR
1534#define STR "HTTP/1.0 401 Unauthorized"
1535    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1536#undef STR
1537    ZEND_PUTS("XCache Auth Failed. User and Password is case sense\n");
1538
1539    zend_bailout();
1540    return 0;
1541}
1542/* }}} */
1543/* {{{ xcache_admin_operate */
[1]1544typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
[34]1545static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
[1]1546{
1547    long type;
1548    int size;
1549    xc_cache_t **caches, *cache;
1550    long id = 0;
1551
[279]1552    xcache_admin_auth_check(TSRMLS_C);
1553
[11]1554    if (!xc_initized) {
[279]1555        RETURN_NULL();
[11]1556    }
1557
[1]1558    if (optype == XC_OP_COUNT) {
1559        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
1560            return;
1561        }
1562    }
1563    else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
1564        return;
1565    }
1566
1567    switch (type) {
1568        case XC_TYPE_PHP:
1569            size = xc_php_hcache.size;
1570            caches = xc_php_caches;
1571            break;
1572
1573        case XC_TYPE_VAR:
1574            size = xc_var_hcache.size;
1575            caches = xc_var_caches;
1576            break;
1577
1578        default:
1579            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
1580            RETURN_FALSE;
1581    }
1582
1583    switch (optype) {
1584        case XC_OP_COUNT:
1585            RETURN_LONG(size)
1586            break;
1587
1588        case XC_OP_INFO:
1589        case XC_OP_LIST:
1590            if (id < 0 || id >= size) {
1591                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1592                RETURN_FALSE;
1593            }
1594
1595            array_init(return_value);
1596
1597            cache = caches[id];
1598            ENTER_LOCK(cache) {
1599                if (optype == XC_OP_INFO) {
[118]1600                    xc_fillinfo_dmz(type, cache, return_value TSRMLS_CC);
[1]1601                }
1602                else {
1603                    xc_filllist_dmz(cache, return_value TSRMLS_CC);
1604                }
1605            } LEAVE_LOCK(cache);
1606            break;
1607        case XC_OP_CLEAR:
1608            {
[141]1609                xc_entry_t *e, *next;
[1]1610                int i, c;
1611
1612                if (id < 0 || id >= size) {
1613                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1614                    RETURN_FALSE;
1615                }
1616
1617                cache = caches[id];
1618                ENTER_LOCK(cache) {
1619                    for (i = 0, c = cache->hentry->size; i < c; i ++) {
[141]1620                        for (e = cache->entries[i]; e; e = next) {
1621                            next = e->next;
[1]1622                            xc_entry_remove_dmz(e TSRMLS_CC);
1623                        }
1624                        cache->entries[i] = NULL;
1625                    }
1626                } LEAVE_LOCK(cache);
[114]1627                xc_gc_deletes(TSRMLS_C);
[1]1628            }
1629            break;
1630
1631        default:
1632            assert(0);
1633    }
1634}
1635/* }}} */
[9]1636/* {{{ proto int xcache_count(int type)
1637   Return count of cache on specified cache type */
[1]1638PHP_FUNCTION(xcache_count)
1639{
[34]1640    xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1641}
1642/* }}} */
[9]1643/* {{{ proto array xcache_info(int type, int id)
1644   Get cache info by id on specified cache type */
[1]1645PHP_FUNCTION(xcache_info)
1646{
[34]1647    xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1648}
1649/* }}} */
[9]1650/* {{{ proto array xcache_list(int type, int id)
1651   Get cache entries list by id on specified cache type */
[1]1652PHP_FUNCTION(xcache_list)
1653{
[34]1654    xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1655}
1656/* }}} */
[9]1657/* {{{ proto array xcache_clear_cache(int type, int id)
1658   Clear cache by id on specified cache type */
[1]1659PHP_FUNCTION(xcache_clear_cache)
1660{
[34]1661    xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1662}
1663/* }}} */
1664
1665static int xc_entry_init_key_var(xc_entry_t *xce, zval *name TSRMLS_DC) /* {{{ */
1666{
1667    xc_hash_value_t hv;
1668    int cacheid;
1669
1670    switch (Z_TYPE_P(name)) {
1671#ifdef IS_UNICODE
1672        case IS_UNICODE:
1673#endif
1674        case IS_STRING:
1675            break;
1676        default:
1677#ifdef IS_UNICODE
1678            convert_to_text(name);
1679#else
1680            convert_to_string(name);
1681#endif
1682    }
1683#ifdef IS_UNICODE
1684    xce->name_type = name->type;
1685#endif
1686    xce->name = name->value;
1687
[152]1688    hv = xc_entry_hash_var(xce TSRMLS_CC);
[1]1689
1690    cacheid = (hv & xc_var_hcache.mask);
1691    xce->cache = xc_var_caches[cacheid];
1692    hv >>= xc_var_hcache.bits;
1693    xce->hvalue = (hv & xc_var_hentry.mask);
1694
1695    xce->type = XC_TYPE_VAR;
1696    return SUCCESS;
1697}
1698/* }}} */
[9]1699/* {{{ proto mixed xcache_get(string name)
1700   Get cached data by specified name */
[1]1701PHP_FUNCTION(xcache_get)
1702{
1703    xc_entry_t xce, *stored_xce;
1704    xc_entry_data_var_t var;
1705    zval *name;
1706
1707    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1708        return;
1709    }
1710    xce.data.var = &var;
1711    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1712
1713    ENTER_LOCK(xce.cache) {
1714        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1715        if (stored_xce) {
[254]1716            if (!VAR_ENTRY_EXPIRED(stored_xce)) {
[233]1717                xc_processor_restore_zval(return_value, stored_xce->data.var->value, stored_xce->have_references TSRMLS_CC);
[1]1718                /* return */
1719                break;
1720            }
1721            else {
[11]1722                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1723            }
1724        }
1725
1726        RETVAL_NULL();
1727    } LEAVE_LOCK(xce.cache);
1728}
1729/* }}} */
[9]1730/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
1731   Store data to cache by specified name */
[1]1732PHP_FUNCTION(xcache_set)
1733{
1734    xc_entry_t xce, *stored_xce;
1735    xc_entry_data_var_t var;
1736    zval *name;
1737    zval *value;
1738
[114]1739    xce.ttl = XG(var_ttl);
1740    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &xce.ttl) == FAILURE) {
[1]1741        return;
1742    }
[114]1743
1744    /* max ttl */
1745    if (xc_var_maxttl && (!xce.ttl || xce.ttl > xc_var_maxttl)) {
1746        xce.ttl = xc_var_maxttl;
1747    }
1748
[1]1749    xce.data.var = &var;
1750    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1751
1752    ENTER_LOCK(xce.cache) {
1753        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1754        if (stored_xce) {
[11]1755            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1756        }
1757        var.value = value;
[11]1758        RETVAL_BOOL(xc_entry_store_dmz(&xce TSRMLS_CC) != NULL ? 1 : 0);
[1]1759    } LEAVE_LOCK(xce.cache);
1760}
1761/* }}} */
[9]1762/* {{{ proto bool  xcache_isset(string name)
1763   Check if an entry exists in cache by specified name */
[1]1764PHP_FUNCTION(xcache_isset)
1765{
1766    xc_entry_t xce, *stored_xce;
1767    xc_entry_data_var_t var;
1768    zval *name;
1769
1770    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1771        return;
1772    }
1773    xce.data.var = &var;
1774    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1775
1776    ENTER_LOCK(xce.cache) {
1777        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1778        if (stored_xce) {
[126]1779            if (!VAR_ENTRY_EXPIRED(stored_xce)) {
[1]1780                RETVAL_TRUE;
1781                /* return */
1782                break;
1783            }
1784            else {
[11]1785                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1786            }
1787        }
1788
1789        RETVAL_FALSE;
1790    } LEAVE_LOCK(xce.cache);
1791}
1792/* }}} */
[9]1793/* {{{ proto bool  xcache_unset(string name)
1794   Unset existing data in cache by specified name */
[1]1795PHP_FUNCTION(xcache_unset)
1796{
1797    xc_entry_t xce, *stored_xce;
1798    xc_entry_data_var_t var;
1799    zval *name;
1800
1801    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1802        return;
1803    }
1804    xce.data.var = &var;
1805    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1806
1807    ENTER_LOCK(xce.cache) {
1808        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1809        if (stored_xce) {
[11]1810            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1811            RETVAL_TRUE;
1812        }
1813        else {
1814            RETVAL_FALSE;
1815        }
1816    } LEAVE_LOCK(xce.cache);
1817}
1818/* }}} */
1819static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
1820{
1821    xc_entry_t xce, *stored_xce;
1822    xc_entry_data_var_t var, *stored_var;
1823    zval *name;
1824    long count = 1;
1825    long value = 0;
1826    zval oldzval;
1827
[114]1828    xce.ttl = XG(var_ttl);
1829    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &xce.ttl) == FAILURE) {
[1]1830        return;
1831    }
[114]1832
1833    /* max ttl */
1834    if (xc_var_maxttl && (!xce.ttl || xce.ttl > xc_var_maxttl)) {
1835        xce.ttl = xc_var_maxttl;
1836    }
1837
[1]1838    xce.data.var = &var;
1839    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1840
1841    ENTER_LOCK(xce.cache) {
1842        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1843        if (stored_xce) {
[305]1844            TRACE("incdec: gotxce %s", xce.name.str.val);
[1]1845            /* timeout */
[114]1846            if (VAR_ENTRY_EXPIRED(stored_xce)) {
[305]1847                TRACE("%s", "incdec: expired");
[11]1848                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1849                stored_xce = NULL;
1850            }
1851            else {
1852                /* do it in place */
[114]1853                stored_var = stored_xce->data.var;
[1]1854                if (Z_TYPE_P(stored_var->value) == IS_LONG) {
[114]1855                    stored_xce->ctime = XG(request_time);
1856                    stored_xce->ttl   = xce.ttl;
[305]1857                    TRACE("%s", "incdec: islong");
[1]1858                    value = Z_LVAL_P(stored_var->value);
1859                    value += (inc == 1 ? count : - count);
1860                    RETVAL_LONG(value);
1861                    Z_LVAL_P(stored_var->value) = value;
[114]1862                    break; /* leave lock */
[1]1863                }
1864                else {
[305]1865                    TRACE("%s", "incdec: notlong");
[233]1866                    xc_processor_restore_zval(&oldzval, stored_xce->data.var->value, stored_xce->have_references TSRMLS_CC);
[1]1867                    convert_to_long(&oldzval);
1868                    value = Z_LVAL(oldzval);
1869                    zval_dtor(&oldzval);
1870                }
1871            }
1872        }
1873        else {
[305]1874            TRACE("incdec: %s not found", xce.name.str.val);
[1]1875        }
1876
1877        value += (inc == 1 ? count : - count);
1878        RETVAL_LONG(value);
1879        var.value = return_value;
[114]1880
[1]1881        if (stored_xce) {
1882            xce.atime = stored_xce->atime;
1883            xce.ctime = stored_xce->ctime;
1884            xce.hits  = stored_xce->hits;
[11]1885            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1886        }
[11]1887        xc_entry_store_dmz(&xce TSRMLS_CC);
[1]1888
1889    } LEAVE_LOCK(xce.cache);
1890}
1891/* }}} */
[9]1892/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
1893   Increase an int counter in cache by specified name, create it if not exists */
[1]1894PHP_FUNCTION(xcache_inc)
1895{
1896    xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1897}
1898/* }}} */
[9]1899/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
1900   Decrease an int counter in cache by specified name, create it if not exists */
[1]1901PHP_FUNCTION(xcache_dec)
1902{
1903    xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1904}
1905/* }}} */
[9]1906/* {{{ proto string xcache_asm(string filename)
1907 */
[1]1908#ifdef HAVE_XCACHE_ASSEMBLER
1909PHP_FUNCTION(xcache_asm)
1910{
1911}
1912#endif
1913/* }}} */
1914#ifdef HAVE_XCACHE_DISASSEMBLER
[9]1915/* {{{ proto array  xcache_dasm_file(string filename)
1916   Disassemble file into opcode array by filename */
[1]1917PHP_FUNCTION(xcache_dasm_file)
1918{
1919    char *filename;
[143]1920    int filename_len;
[1]1921
1922    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1923        return;
1924    }
1925    if (!filename_len) RETURN_FALSE;
1926
1927    xc_dasm_file(return_value, filename TSRMLS_CC);
1928}
1929/* }}} */
[9]1930/* {{{ proto array  xcache_dasm_string(string code)
1931   Disassemble php code into opcode array */
[1]1932PHP_FUNCTION(xcache_dasm_string)
1933{
1934    zval *code;
1935
1936    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
1937        return;
1938    }
1939    xc_dasm_string(return_value, code TSRMLS_CC);
1940}
1941/* }}} */
1942#endif
[9]1943/* {{{ proto string xcache_encode(string filename)
1944   Encode php file into XCache opcode encoded format */
[1]1945#ifdef HAVE_XCACHE_ENCODER
1946PHP_FUNCTION(xcache_encode)
1947{
1948}
1949#endif
1950/* }}} */
[9]1951/* {{{ proto bool xcache_decode_file(string filename)
1952   Decode(load) opcode from XCache encoded format file */
[1]1953#ifdef HAVE_XCACHE_DECODER
[9]1954PHP_FUNCTION(xcache_decode_file)
[1]1955{
1956}
1957#endif
1958/* }}} */
[9]1959/* {{{ proto bool xcache_decode_string(string data)
1960   Decode(load) opcode from XCache encoded format data */
1961#ifdef HAVE_XCACHE_DECODER
1962PHP_FUNCTION(xcache_decode_string)
1963{
1964}
1965#endif
1966/* }}} */
[1]1967/* {{{ xc_call_getter */
1968typedef const char *(xc_name_getter_t)(zend_uchar type);
1969static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
1970{
1971    long spec;
1972    const char *name;
1973
1974    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1975        return;
1976    }
1977    if (spec >= 0 && spec < count) {
[11]1978        name = getter((zend_uchar) spec);
[1]1979        if (name) {
1980            /* RETURN_STRING */
1981            int len = strlen(name);
1982            return_value->value.str.len = len;
1983            return_value->value.str.val = estrndup(name, len);
1984            return_value->type = IS_STRING; 
1985            return;
1986        }
1987    }
1988    RETURN_NULL();
1989}
1990/* }}} */
1991/* {{{ proto string xcache_get_op_type(int op_type) */
1992PHP_FUNCTION(xcache_get_op_type)
1993{
1994    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1995}
1996/* }}} */
1997/* {{{ proto string xcache_get_data_type(int type) */
1998PHP_FUNCTION(xcache_get_data_type)
1999{
2000    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
2001}
2002/* }}} */
2003/* {{{ proto string xcache_get_opcode(int opcode) */
2004PHP_FUNCTION(xcache_get_opcode)
2005{
2006    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
2007}
2008/* }}} */
2009/* {{{ proto string xcache_get_op_spec(int op_type) */
2010PHP_FUNCTION(xcache_get_op_spec)
2011{
2012    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
2013}
2014/* }}} */
[8]2015#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
[1]2016/* {{{ proto string xcache_get_opcode_spec(int opcode) */
2017PHP_FUNCTION(xcache_get_opcode_spec)
2018{
2019    long spec;
2020    const xc_opcode_spec_t *opspec;
2021
2022    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
2023        return;
2024    }
[17]2025    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
[11]2026        opspec = xc_get_opcode_spec((zend_uchar) spec);
[1]2027        if (opspec) {
2028            array_init(return_value);
2029            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
2030            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
2031            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
2032            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
2033            return;
2034        }
2035    }
2036    RETURN_NULL();
2037}
2038/* }}} */
[8]2039#endif
[1]2040/* {{{ proto mixed xcache_get_special_value(zval value) */
2041PHP_FUNCTION(xcache_get_special_value)
2042{
2043    zval *value;
2044
2045    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
2046        return;
2047    }
2048
2049    if (value->type == IS_CONSTANT) {
2050        *return_value = *value;
2051        zval_copy_ctor(return_value);
2052        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
2053        return;
2054    }
2055
2056    if (value->type == IS_CONSTANT_ARRAY) {
2057        *return_value = *value;
2058        zval_copy_ctor(return_value);
2059        return_value->type = IS_ARRAY;
2060        return;
2061    }
2062
2063    RETURN_NULL();
2064}
2065/* }}} */
2066/* {{{ proto string xcache_coredump(int op_type) */
2067PHP_FUNCTION(xcache_coredump)
2068{
[9]2069    if (xc_test) {
2070        raise(SIGSEGV);
2071    }
2072    else {
2073        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
2074    }
[1]2075}
2076/* }}} */
2077/* {{{ proto string xcache_is_autoglobal(string name) */
2078PHP_FUNCTION(xcache_is_autoglobal)
2079{
2080    char *name;
[143]2081    int name_len;
[1]2082
2083    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
2084        return;
2085    }
2086
2087    RETURN_BOOL(zend_hash_exists(CG(auto_globals), name, name_len + 1));
2088}
2089/* }}} */
2090static function_entry xcache_functions[] = /* {{{ */
2091{
2092    PHP_FE(xcache_count,             NULL)
2093    PHP_FE(xcache_info,              NULL)
2094    PHP_FE(xcache_list,              NULL)
2095    PHP_FE(xcache_clear_cache,       NULL)
2096    PHP_FE(xcache_coredump,          NULL)
2097#ifdef HAVE_XCACHE_ASSEMBLER
2098    PHP_FE(xcache_asm,               NULL)
2099#endif
2100#ifdef HAVE_XCACHE_DISASSEMBLER
2101    PHP_FE(xcache_dasm_file,         NULL)
2102    PHP_FE(xcache_dasm_string,       NULL)
2103#endif
2104#ifdef HAVE_XCACHE_ENCODER
2105    PHP_FE(xcache_encode,            NULL)
2106#endif
2107#ifdef HAVE_XCACHE_DECODER
[9]2108    PHP_FE(xcache_decode_file,       NULL)
2109    PHP_FE(xcache_decode_string,     NULL)
[1]2110#endif
[27]2111#ifdef HAVE_XCACHE_COVERAGER
2112    PHP_FE(xcache_coverager_decode,  NULL)
[204]2113    PHP_FE(xcache_coverager_start,   NULL)
2114    PHP_FE(xcache_coverager_stop,    NULL)
2115    PHP_FE(xcache_coverager_get,     NULL)
[1]2116#endif
2117    PHP_FE(xcache_get_special_value, NULL)
2118    PHP_FE(xcache_get_op_type,       NULL)
2119    PHP_FE(xcache_get_data_type,     NULL)
2120    PHP_FE(xcache_get_opcode,        NULL)
[8]2121#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
[1]2122    PHP_FE(xcache_get_opcode_spec,   NULL)
[8]2123#endif
[1]2124    PHP_FE(xcache_is_autoglobal,     NULL)
2125    PHP_FE(xcache_inc,               NULL)
2126    PHP_FE(xcache_dec,               NULL)
2127    PHP_FE(xcache_get,               NULL)
2128    PHP_FE(xcache_set,               NULL)
2129    PHP_FE(xcache_isset,             NULL)
2130    PHP_FE(xcache_unset,             NULL)
2131    {NULL, NULL,                     NULL}
2132};
2133/* }}} */
2134
[75]2135/* old signal handlers {{{ */
2136typedef void (*xc_sighandler_t)(int);
2137#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
2138#include "foreachcoresig.h"
2139#undef FOREACH_SIG
2140/* }}} */
2141static void xcache_signal_handler(int sig);
2142static void xcache_restore_signal_handler() /* {{{ */
[1]2143{
[75]2144#define FOREACH_SIG(sig) do { \
2145    if (old_##sig##_handler != xcache_signal_handler) { \
2146        signal(sig, old_##sig##_handler); \
2147    } \
2148    else { \
2149        signal(sig, SIG_DFL); \
2150    } \
2151} while (0)
2152#include "foreachcoresig.h"
2153#undef FOREACH_SIG
2154}
2155/* }}} */
2156static void xcache_init_signal_handler() /* {{{ */
2157{
2158#define FOREACH_SIG(sig) \
2159    old_##sig##_handler = signal(sig, xcache_signal_handler)
2160#include "foreachcoresig.h"
2161#undef FOREACH_SIG
2162}
2163/* }}} */
2164static void xcache_signal_handler(int sig) /* {{{ */
2165{
2166    xcache_restore_signal_handler();
[1]2167    if (xc_coredump_dir && xc_coredump_dir[0]) {
2168        chdir(xc_coredump_dir);
2169    }
[65]2170    raise(sig);
[1]2171}
2172/* }}} */
2173
2174/* {{{ PHP_INI */
2175
[164]2176static PHP_INI_MH(xc_OnUpdateDummy)
2177{
2178    return SUCCESS;
2179}
2180
2181static PHP_INI_MH(xc_OnUpdateULong)
2182{
2183    zend_ulong *p = (zend_ulong *) mh_arg1;
2184
2185    *p = (zend_ulong) atoi(new_value);
2186    return SUCCESS;
2187}
2188
[1]2189static PHP_INI_MH(xc_OnUpdateBool)
2190{
2191    zend_bool *p = (zend_bool *)mh_arg1;
2192
2193    if (strncasecmp("on", new_value, sizeof("on"))) {
2194        *p = (zend_bool) atoi(new_value);
2195    }
2196    else {
2197        *p = (zend_bool) 1;
2198    }
2199    return SUCCESS;
2200}
2201
2202static PHP_INI_MH(xc_OnUpdateString)
2203{
2204    char **p = (char**)mh_arg1;
2205    if (*p) {
2206        pefree(*p, 1);
2207    }
2208    *p = pemalloc(strlen(new_value) + 1, 1);
2209    strcpy(*p, new_value);
2210    return SUCCESS;
2211}
[82]2212
[114]2213#ifndef ZEND_ENGINE_2
2214#define OnUpdateLong OnUpdateInt
[1]2215#endif
2216
[21]2217#ifdef ZEND_WIN32
2218#   define DEFAULT_PATH "xcache"
2219#else
2220#   define DEFAULT_PATH "/dev/zero"
2221#endif
[1]2222PHP_INI_BEGIN()
[21]2223    PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
[1]2224    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
2225    PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
2226    PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
[164]2227    /* opcode cache */
2228    PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2229    PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2230    PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2231    PHP_INI_ENTRY1     ("xcache.shm_scheme",          "mmap", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_shm_scheme)
2232    PHP_INI_ENTRY1     ("xcache.ttl",                    "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_ttl)
2233    PHP_INI_ENTRY1     ("xcache.gc_interval",            "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_gc_interval)
2234    /* var cache */
2235    PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2236    PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2237    PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2238    PHP_INI_ENTRY1     ("xcache.var_maxttl",             "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_maxttl)
2239    PHP_INI_ENTRY1     ("xcache.var_gc_interval",      "120", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_gc_interval)
[1]2240
2241    STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
[165]2242    STD_PHP_INI_BOOLEAN("xcache.stat",                   "1", PHP_INI_ALL,    OnUpdateBool,        stat,              zend_xcache_globals, xcache_globals)
[1]2243#ifdef HAVE_XCACHE_OPTIMIZER
2244    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
2245#endif
[254]2246    STD_PHP_INI_ENTRY  ("xcache.var_ttl",                "0", PHP_INI_ALL,    OnUpdateLong,        var_ttl,           zend_xcache_globals, xcache_globals)
[27]2247#ifdef HAVE_XCACHE_COVERAGER
[204]2248    STD_PHP_INI_BOOLEAN("xcache.coverager"      ,        "0", PHP_INI_ALL,    OnUpdateBool,        coverager,         zend_xcache_globals, xcache_globals)
2249    PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
[1]2250#endif
2251PHP_INI_END()
2252/* }}} */
2253/* {{{ PHP_MINFO_FUNCTION(xcache) */
2254static PHP_MINFO_FUNCTION(xcache)
2255{
[82]2256    char buf[100];
2257    char *ptr;
[163]2258    int left, len;
2259    xc_shm_scheme_t *scheme;
[204]2260    char *covdumpdir;
[82]2261
[1]2262    php_info_print_table_start();
[148]2263    php_info_print_table_header(2, "XCache Support", "enabled");
[1]2264    php_info_print_table_row(2, "Version", XCACHE_VERSION);
[26]2265    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
[1]2266    php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
[82]2267
2268    if (xc_php_size) {
2269        ptr = _php_math_number_format(xc_php_size, 0, '.', ',');
[163]2270        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_php_hcache.size, xc_php_hentry.size);
[82]2271        php_info_print_table_row(2, "Opcode Cache", buf);
2272        efree(ptr);
2273    }
2274    else {
2275        php_info_print_table_row(2, "Opcode Cache", "disabled");
2276    }
2277    if (xc_var_size) {
2278        ptr = _php_math_number_format(xc_var_size, 0, '.', ',');
[163]2279        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_var_hcache.size, xc_var_hentry.size);
[82]2280        php_info_print_table_row(2, "Variable Cache", buf);
2281        efree(ptr);
2282    }
2283    else {
2284        php_info_print_table_row(2, "Variable Cache", "disabled");
2285    }
[163]2286
2287    left = sizeof(buf);
2288    ptr = buf;
2289    buf[0] = '\0';
2290    for (scheme = xc_shm_scheme_first(); scheme; scheme = xc_shm_scheme_next(scheme)) {
2291        len = snprintf(ptr, left, ptr == buf ? "%s" : ", %s", xc_shm_scheme_name(scheme));
2292        left -= len;
2293        ptr += len;
2294    }
2295    php_info_print_table_row(2, "Shared Memory Schemes", buf);
2296
[26]2297#ifdef HAVE_XCACHE_COVERAGER
[204]2298    if (cfg_get_string("xcache.coveragedump_directory", &covdumpdir) != SUCCESS || !covdumpdir[0]) {
2299        covdumpdir = NULL;
2300    }
2301    php_info_print_table_row(2, "Coverage Auto Dumper", XG(coverager) && covdumpdir ? "enabled" : "disabled");
[26]2302#endif
[1]2303    php_info_print_table_end();
[82]2304
[1]2305    DISPLAY_INI_ENTRIES();
2306}
2307/* }}} */
2308/* {{{ extension startup */
2309static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
2310{
2311    zend_extension extension;
2312
2313    extension = *new_extension;
2314    extension.handle = handle;
2315
2316    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
2317
[296]2318    zend_llist_prepend_element(&zend_extensions, &extension);
[305]2319    TRACE("%s", "registered");
[1]2320}
2321
2322static int xc_zend_extension_startup(zend_extension *extension)
2323{
2324    if (extension->startup) {
2325        if (extension->startup(extension) != SUCCESS) {
2326            return FAILURE;
2327        }
2328    }
2329    return SUCCESS;
2330}
2331/* }}} */
[278]2332static int xc_ptr_compare_func(void *p1, void *p2) /* {{{ */
2333{
2334    return p1 == p2;
2335}
2336/* }}} */
2337static int xc_zend_remove_extension(zend_extension *extension) /* {{{ */
2338{
2339    llist_dtor_func_t dtor;
2340
2341    assert(extension);
2342    dtor = zend_extensions.dtor; /* avoid dtor */
2343    zend_extensions.dtor = NULL;
2344    zend_llist_del_element(&zend_extensions, extension, xc_ptr_compare_func);
2345    zend_extensions.dtor = dtor;
[295]2346    return SUCCESS;
[278]2347}
2348/* }}} */
[82]2349static int xc_config_hash(xc_hash_t *p, char *name, char *default_value) /* {{{ */
2350{
2351    int bits, size;
2352    char *value;
2353
2354    if (cfg_get_string(name, &value) != SUCCESS) {
2355        value = default_value;
2356    }
2357
2358    p->size = zend_atoi(value, strlen(value));
2359    for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
2360        /* empty body */
2361    }
2362    p->size = size;
2363    p->bits = bits;
2364    p->mask = size - 1;
2365
2366    return SUCCESS;
2367}
2368/* }}} */
[90]2369static int xc_config_long(zend_ulong *p, char *name, char *default_value) /* {{{ */
[82]2370{
2371    char *value;
2372
2373    if (cfg_get_string(name, &value) != SUCCESS) {
2374        value = default_value;
2375    }
2376
2377    *p = zend_atoi(value, strlen(value));
2378    return SUCCESS;
2379}
2380/* }}} */
[1]2381/* {{{ PHP_MINIT_FUNCTION(xcache) */
2382static PHP_MINIT_FUNCTION(xcache)
2383{
2384    char *env;
[189]2385    zend_extension *ext;
2386    zend_llist_position lpos;
[1]2387
2388    xc_module_gotup = 1;
2389    if (!xc_zend_extension_gotup) {
[296]2390        xc_zend_extension_register(&zend_extension_entry, 0);
2391        xc_zend_extension_startup(&zend_extension_entry);
2392        xc_zend_extension_faked = 1;
[1]2393    }
2394
[190]2395    ext = zend_get_extension("Zend Optimizer");
2396    if (ext) {
2397        /* zend_optimizer.optimization_level>0 is not compatible with other cacher, disabling */
2398        ext->op_array_handler = NULL;
2399    }
[189]2400    /* cache if there's an op_array_ctor */
2401    for (ext = zend_llist_get_first_ex(&zend_extensions, &lpos);
2402            ext;
2403            ext = zend_llist_get_next_ex(&zend_extensions, &lpos)) {
2404        if (ext->op_array_ctor) {
2405            xc_have_op_array_ctor = 1;
2406            break;
2407        }
2408    }
2409
2410
[92]2411#ifndef PHP_GINIT
[17]2412    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
[92]2413#endif
[17]2414    REGISTER_INI_ENTRIES();
2415
[1]2416    if (strcmp(sapi_module.name, "cli") == 0) {
2417        if ((env = getenv("XCACHE_TEST")) != NULL) {
2418            zend_alter_ini_entry("xcache.test", sizeof("xcache.test"), env, strlen(env) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP);
2419        }
2420        if (!xc_test) {
2421            /* disable cache for cli except for test */
2422            xc_php_size = xc_var_size = 0;
2423        }
2424    }
2425
[114]2426    xc_config_long(&xc_php_size,       "xcache.size",        "0");
2427    xc_config_hash(&xc_php_hcache,     "xcache.count",       "1");
2428    xc_config_hash(&xc_php_hentry,     "xcache.slots",      "8K");
[82]2429
[164]2430    xc_config_long(&xc_var_size,       "xcache.var_size",    "0");
2431    xc_config_hash(&xc_var_hcache,     "xcache.var_count",   "1");
2432    xc_config_hash(&xc_var_hentry,     "xcache.var_slots",  "8K");
[82]2433
[1]2434    if (xc_php_size <= 0) {
2435        xc_php_size = xc_php_hcache.size = 0;
2436    }
2437    if (xc_var_size <= 0) {
2438        xc_var_size = xc_var_hcache.size = 0;
2439    }
2440
[65]2441    if (xc_coredump_dir && xc_coredump_dir[0]) {
[75]2442        xcache_init_signal_handler();
[65]2443    }
[1]2444
2445    xc_init_constant(module_number TSRMLS_CC);
[148]2446    xc_shm_init_modules();
[1]2447
2448    if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
2449        if (!xc_init(module_number TSRMLS_CC)) {
[21]2450            zend_error(E_ERROR, "XCache: Cannot init");
[1]2451            goto err_init;
2452        }
2453        xc_initized = 1;
2454    }
2455
[27]2456#ifdef HAVE_XCACHE_COVERAGER
2457    xc_coverager_init(module_number TSRMLS_CC);
[1]2458#endif
2459
2460    return SUCCESS;
2461
2462err_init:
2463    return FAILURE;
2464}
2465/* }}} */
2466/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
2467static PHP_MSHUTDOWN_FUNCTION(xcache)
2468{
2469    if (xc_initized) {
2470        xc_destroy();
2471        xc_initized = 0;
2472    }
2473    if (xc_mmap_path) {
2474        pefree(xc_mmap_path, 1);
2475        xc_mmap_path = NULL;
2476    }
[148]2477    if (xc_shm_scheme) {
2478        pefree(xc_shm_scheme, 1);
2479        xc_shm_scheme = NULL;
2480    }
[1]2481
[27]2482#ifdef HAVE_XCACHE_COVERAGER
2483    xc_coverager_destroy();
[1]2484#endif
2485
[65]2486    if (xc_coredump_dir && xc_coredump_dir[0]) {
[75]2487        xcache_restore_signal_handler();
[65]2488    }
[1]2489    if (xc_coredump_dir) {
2490        pefree(xc_coredump_dir, 1);
2491        xc_coredump_dir = NULL;
2492    }
[92]2493#ifndef PHP_GINIT
2494#   ifdef ZTS
[25]2495    ts_free_id(xcache_globals_id);
[92]2496#   else
[1]2497    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
[92]2498#   endif
[1]2499#endif
2500
[278]2501    if (xc_zend_extension_faked) {
2502        zend_extension *ext = zend_get_extension(XCACHE_NAME);
2503        if (ext->shutdown) {
2504            ext->shutdown(ext);
2505        }
2506        xc_zend_remove_extension(ext);
2507    }
[1]2508    UNREGISTER_INI_ENTRIES();
2509    return SUCCESS;
2510}
2511/* }}} */
2512/* {{{ PHP_RINIT_FUNCTION(xcache) */
2513static PHP_RINIT_FUNCTION(xcache)
2514{
2515    xc_request_init(TSRMLS_C);
2516    return SUCCESS;
2517}
2518/* }}} */
2519/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
2520#ifndef ZEND_ENGINE_2
2521static PHP_RSHUTDOWN_FUNCTION(xcache)
2522#else
2523static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
2524#endif
2525{
[18]2526#ifdef ZEND_ENGINE_2
[11]2527    TSRMLS_FETCH();
[18]2528#endif
[11]2529
[1]2530    xc_request_shutdown(TSRMLS_C);
2531    return SUCCESS;
2532}
2533/* }}} */
2534/* {{{ module definition structure */
2535
2536zend_module_entry xcache_module_entry = {
2537    STANDARD_MODULE_HEADER,
[21]2538    "XCache",
[1]2539    xcache_functions,
2540    PHP_MINIT(xcache),
2541    PHP_MSHUTDOWN(xcache),
2542    PHP_RINIT(xcache),
2543#ifndef ZEND_ENGINE_2
2544    PHP_RSHUTDOWN(xcache),
2545#else
2546    NULL,
2547#endif
2548    PHP_MINFO(xcache),
2549    XCACHE_VERSION,
[92]2550#ifdef PHP_GINIT
2551    PHP_MODULE_GLOBALS(xcache),
2552    PHP_GINIT(xcache),
2553    PHP_GSHUTDOWN(xcache),
2554#endif
[1]2555#ifdef ZEND_ENGINE_2
2556    ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
2557#else
2558    NULL,
2559    NULL,
2560#endif
2561    STANDARD_MODULE_PROPERTIES_EX
2562};
2563
2564#ifdef COMPILE_DL_XCACHE
2565ZEND_GET_MODULE(xcache)
2566#endif
2567/* }}} */
[190]2568static startup_func_t xc_last_ext_startup;
2569static zend_llist_element *xc_llist_element;
2570static int xc_zend_startup_last(zend_extension *extension) /* {{{ */
2571{
2572    /* restore */
2573    extension->startup = xc_last_ext_startup;
2574    if (extension->startup) {
2575        if (extension->startup(extension) != SUCCESS) {
2576            return FAILURE;
2577        }
2578    }
2579    xc_zend_extension_register(&zend_extension_entry, 0);
2580    if (!xc_module_gotup) {
2581        return zend_startup_module(&xcache_module_entry);
2582    }
2583    return SUCCESS;
2584}
2585/* }}} */
[1]2586ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
2587{
2588    xc_zend_extension_gotup = 1;
[190]2589    xc_llist_element = NULL;
2590    if (zend_llist_count(&zend_extensions) > 1) {
2591        zend_llist_position lpos;
2592        zend_extension *ext;
2593
2594        ext = zend_get_extension(XCACHE_NAME);
[278]2595        xc_zend_remove_extension(ext);
[190]2596
2597        ext = (zend_extension *) zend_llist_get_last_ex(&zend_extensions, &lpos);
2598        assert(ext);
2599        xc_last_ext_startup = ext->startup;
2600        ext->startup = xc_zend_startup_last;
2601    }
2602    else if (!xc_module_gotup) {
[1]2603        return zend_startup_module(&xcache_module_entry);
2604    }
2605    return SUCCESS;
2606}
2607/* }}} */
2608ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
2609{
2610    /* empty */
2611}
2612/* }}} */
2613ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
2614{
[27]2615#ifdef HAVE_XCACHE_COVERAGER
2616    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
[1]2617#endif
2618}
2619/* }}} */
2620ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
2621{
2622#if 0
[27]2623    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
[1]2624#endif
2625}
2626/* }}} */
2627ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
2628{
2629#if 0
[27]2630    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
[1]2631#endif
2632}
2633/* }}} */
2634/* {{{ zend extension definition structure */
2635ZEND_DLEXPORT zend_extension zend_extension_entry = {
2636    XCACHE_NAME,
2637    XCACHE_VERSION,
2638    XCACHE_AUTHOR,
2639    XCACHE_URL,
2640    XCACHE_COPYRIGHT,
2641    xcache_zend_startup,
2642    xcache_zend_shutdown,
2643    NULL,           /* activate_func_t */
2644    NULL,           /* deactivate_func_t */
2645    NULL,           /* message_handler_func_t */
2646    NULL,           /* op_array_handler_func_t */
2647    xcache_statement_handler,
2648    xcache_fcall_begin_handler,
2649    xcache_fcall_end_handler,
2650    NULL,           /* op_array_ctor_func_t */
2651    NULL,           /* op_array_dtor_func_t */
2652    STANDARD_ZEND_EXTENSION_PROPERTIES
2653};
2654
2655#ifndef ZEND_EXT_API
2656#   define ZEND_EXT_API ZEND_DLEXPORT
2657#endif
2658#if COMPILE_DL_XCACHE
2659ZEND_EXTENSION();
2660#endif
2661/* }}} */
Note: See TracBrowser for help on using the repository browser.