source: trunk/xcache.c @ 163

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

show available shm scheme in moduleinfo

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