source: trunk/xcache.c @ 143

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

fixed string parameter parsing arg type for disassembler functions. thanks to Nuno Lopes' check_parameters.php

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