source: trunk/xcache.c @ 146

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

avoid reading of uninitialized data. thanks to valgrind

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