source: trunk/xcache.c @ 17

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

void circle dependcy between ZEND_INIT_MODULE_GLOBALS and REGISTER_INI_ENTRIES

File size: 48.3 KB
Line 
1
2#undef DEBUG
3
4/* {{{ macros */
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8
9#include <malloc.h>
10#include <signal.h>
11
12#include "php.h"
13#include "ext/standard/info.h"
14#include "zend_extensions.h"
15#include "SAPI.h"
16
17#include "xcache.h"
18#include "optimizer.h"
19#include "coverage.h"
20#include "disassembler.h"
21#include "align.h"
22#include "stack.h"
23#include "xcache_globals.h"
24#include "processor.h"
25#include "utils.h"
26#include "const_string.h"
27#include "opcode_spec.h"
28
29#undef NDEBUG
30#ifdef DEBUG
31#   undef inline
32#   define inline
33#else
34#   define NDEBUG
35#endif
36#include <assert.h>
37
38#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
39#define LOCK(x) xc_lock(x->lck)
40#define UNLOCK(x) xc_unlock(x->lck)
41#define ENTER_LOCK(x) do { \
42    int catched = 0; \
43    xc_lock(x->lck); \
44    zend_try { \
45        do
46#define LEAVE_LOCK(x) \
47        while (0); \
48    } zend_catch { \
49        catched = 1; \
50    } zend_end_try(); \
51    xc_unlock(x->lck); \
52} while(0)
53/* }}} */
54
55/* {{{ globals */
56static char *xc_mmap_path = NULL;
57static char *xc_coredump_dir = NULL;
58
59static xc_hash_t xc_php_hcache = {0};
60static xc_hash_t xc_php_hentry = {0};
61static xc_hash_t xc_var_hcache = {0};
62static xc_hash_t xc_var_hentry = {0};
63
64/* total size */
65static zend_ulong xc_php_size  = 0;
66static zend_ulong xc_var_size  = 0;
67
68static xc_cache_t **xc_php_caches = NULL;
69static xc_cache_t **xc_var_caches = NULL;
70
71static zend_bool xc_initized = 0;
72static zend_compile_file_t *origin_compile_file;
73
74static zend_bool xc_test = 0;
75static zend_bool xc_readonly_protection = 0;
76
77static zend_bool xc_module_gotup = 0;
78static zend_bool xc_zend_extension_gotup = 0;
79#if !COMPILE_DL_XCACHE
80#   define zend_extension_entry xcache_zend_extension_entry
81#endif
82ZEND_DLEXPORT zend_extension zend_extension_entry;
83ZEND_DECLARE_MODULE_GLOBALS(xcache);
84/* }}} */
85
86/* any function in *_dmz is only safe be called within locked(single thread) area */
87
88static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
89{
90    /* this function isn't required but can be in dmz */
91
92    if (a->type != b->type) {
93        return 0;
94    }
95    switch (a->type) {
96        case XC_TYPE_PHP:
97#ifdef HAVE_INODE
98            do {
99                xc_entry_data_php_t *ap = a->data.php;
100                xc_entry_data_php_t *bp = b->data.php;
101                return ap->inode == bp->inode
102                    && ap->device == bp->device;
103            } while(0);
104#endif
105            /* fall */
106
107        case XC_TYPE_VAR:
108            do {
109#ifdef IS_UNICODE
110                if (a->name_type == IS_UNICODE) {
111                    if (a->name.ustr.len != b->name.ustr.len) {
112                        return 0;
113                    }
114                    return memcmp(a->name.ustr.val, b->name.ustr.val, (a->name.ustr.len + 1) * sizeof(UChar)) == 0;
115                }
116                else {
117                    return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
118                }
119#else
120                return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
121#endif
122
123            } while(0);
124        default:
125            assert(0);
126    }
127    return 0;
128}
129/* }}} */
130static void xc_entry_free_dmz(volatile xc_entry_t *xce) /* {{{ */
131{
132    xc_mem_free(xce->cache->mem, (xc_entry_t *)xce);
133}
134/* }}} */
135static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */
136{
137    xc_entry_t **head = &(xce->cache->entries[xce->hvalue]);
138    xce->next = *head;
139    *head = xce;
140}
141/* }}} */
142static xc_entry_t *xc_entry_store_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
143{
144    xc_entry_t *stored_xce;
145
146    xce->hits  = 0;
147    xce->ctime = XG(request_time);
148    xce->atime = XG(request_time);
149    stored_xce = xc_processor_store_xc_entry_t(xce TSRMLS_CC);
150    if (stored_xce) {
151        xc_entry_add_dmz(stored_xce);
152        return stored_xce;
153    }
154    else {
155        xce->cache->ooms ++;
156        return NULL;
157    }
158}
159/* }}} */
160static void xc_entry_remove_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
161{
162    xc_entry_t **last = &(xce->cache->entries[xce->hvalue]);
163    xc_entry_t *p;
164    for (p = *last; p; last = &(p->next), p = p->next) {
165        if (xc_entry_equal_dmz(xce, p)) {
166            *last = p->next;
167            if (p->refcount == 0) {
168                xc_entry_free_dmz(p);
169            }
170            else {
171                p->next = p->cache->deletes;
172                p->cache->deletes = p;
173                p->dtime = XG(request_time);
174            }
175            return;
176        }
177    }
178    assert(0);
179}
180/* }}} */
181static xc_entry_t *xc_entry_find_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
182{
183    xc_entry_t *p;
184    for (p = xce->cache->entries[xce->hvalue]; p; p = p->next) {
185        if (xc_entry_equal_dmz(xce, p)) {
186            if (p->type == XC_TYPE_VAR || /* PHP */ p->data.php->mtime == xce->data.php->mtime) {
187                p->hits ++;
188                p->atime = XG(request_time);
189                return p;
190            }
191            else {
192                xc_entry_remove_dmz(p TSRMLS_CC);
193                return NULL;
194            }
195        }
196    }
197    return NULL;
198}
199/* }}} */
200static void xc_entry_hold_php_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
201{
202    xce->refcount ++;
203    xc_stack_push(&XG(php_holds)[xce->cache->cacheid], (void *)xce);
204}
205/* }}} */
206#if 0
207static void xc_entry_hold_var_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
208{
209    xce->refcount ++;
210    xc_stack_push(&XG(var_holds)[xce->cache->cacheid], (void *)xce);
211}
212/* }}} */
213#endif
214
215/* helper functions for user functions */
216static void xc_fillinfo_dmz(xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
217{
218    zval *blocks;
219    const xc_block_t *b;
220#ifndef NDEBUG
221    xc_memsize_t avail = 0;
222#endif
223    xc_mem_t *mem = cache->mem;
224    int i, c, count;
225    xc_entry_t *e;
226
227    add_assoc_long_ex(return_value, ZEND_STRS("slots"),     cache->hentry->size);
228    add_assoc_long_ex(return_value, ZEND_STRS("compiling"), cache->compiling);
229    add_assoc_long_ex(return_value, ZEND_STRS("misses"),    cache->misses);
230    add_assoc_long_ex(return_value, ZEND_STRS("hits"),      cache->hits);
231    add_assoc_long_ex(return_value, ZEND_STRS("clogs"),     cache->clogs);
232    add_assoc_long_ex(return_value, ZEND_STRS("ooms"),      cache->ooms);
233
234    count = 0;
235    for (i = 0, c = cache->hentry->size; i < c; i ++) {
236        for (e = cache->entries[i]; e; e = e->next) {
237            count ++;
238        }
239    }
240    add_assoc_long_ex(return_value, ZEND_STRS("cached"), count);
241
242    count = 0;
243    for (e = cache->deletes; e; e = e->next) {
244        count ++;
245    }
246    add_assoc_long_ex(return_value, ZEND_STRS("deleted"), count);
247
248    MAKE_STD_ZVAL(blocks);
249    array_init(blocks);
250
251    add_assoc_long_ex(return_value, ZEND_STRS("size"),  xc_mem_size(mem));
252    add_assoc_long_ex(return_value, ZEND_STRS("avail"), xc_mem_avail(mem));
253    add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection);
254
255    for (b = xc_mem_freeblock_first(mem); b; b = xc_mem_freeblock_next(b)) {
256        zval *bi;
257
258        MAKE_STD_ZVAL(bi);
259        array_init(bi);
260
261        add_assoc_long_ex(bi, ZEND_STRS("size"),   xc_mem_block_size(b));
262        add_assoc_long_ex(bi, ZEND_STRS("offset"), xc_mem_block_offset(mem, b));
263        add_next_index_zval(blocks, bi);
264#ifndef NDEBUG
265        avail += b->size;
266#endif
267    }
268    add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks);
269    assert(avail == xc_mem_avail(mem));
270}
271/* }}} */
272static void xc_fillentry_dmz(xc_entry_t *entry, int del, zval *list TSRMLS_DC) /* {{{ */
273{
274    zval* ei;
275    xc_entry_data_php_t *php;
276    xc_entry_data_var_t *var;
277
278    ALLOC_INIT_ZVAL(ei);
279    array_init(ei);
280
281    add_assoc_long_ex(ei, ZEND_STRS("size"),     entry->size);
282    add_assoc_long_ex(ei, ZEND_STRS("refcount"), entry->refcount);
283    add_assoc_long_ex(ei, ZEND_STRS("hits"),     entry->hits);
284    add_assoc_long_ex(ei, ZEND_STRS("ctime"),    entry->ctime);
285    add_assoc_long_ex(ei, ZEND_STRS("atime"),    entry->atime);
286    add_assoc_long_ex(ei, ZEND_STRS("dtime"),    entry->dtime);
287#ifdef IS_UNICODE
288    do {
289        zval *zv;
290        ALLOC_INIT_ZVAL(zv);
291        switch (entry->name_type) {
292            case IS_UNICODE:
293                    ZVAL_UNICODEL(zv, entry->name.ustr.val, entry->name.ustr.len, 1);
294                break;
295            case IS_STRING:
296                ZVAL_STRINGL(zv, entry->name.str.val, entry->name.str.len, 1);
297                break;
298            default:
299                assert(0);
300        }
301        zv->type = entry->name_type;
302        add_assoc_zval_ex(ei, ZEND_STRS("name"), zv);
303    } while (0);
304#else
305    add_assoc_stringl_ex(ei, ZEND_STRS("name"), entry->name.str.val, entry->name.str.len + 1, 1);
306#endif
307    switch (entry->type) {
308        case XC_TYPE_PHP:
309            php = entry->data.php;
310            add_assoc_long_ex(ei, ZEND_STRS("sourcesize"),   php->sourcesize);
311#ifdef HAVE_INODE
312            add_assoc_long_ex(ei, ZEND_STRS("device"),       php->device);
313            add_assoc_long_ex(ei, ZEND_STRS("inode"),        php->inode);
314#endif
315            add_assoc_long_ex(ei, ZEND_STRS("mtime"),        php->mtime);
316
317            add_assoc_long_ex(ei, ZEND_STRS("function_cnt"), php->funcinfo_cnt);
318            add_assoc_long_ex(ei, ZEND_STRS("class_cnt"),    php->classinfo_cnt);
319            break;
320        case XC_TYPE_VAR:
321            var = entry->data.var;
322            break;
323
324        default:
325            assert(0);
326    }
327
328    add_next_index_zval(list, ei);
329}
330/* }}} */
331static void xc_filllist_dmz(xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
332{
333    zval* list;
334    int i, c;
335    xc_entry_t *e;
336
337    ALLOC_INIT_ZVAL(list);
338    array_init(list);
339
340    for (i = 0, c = cache->hentry->size; i < c; i ++) {
341        for (e = cache->entries[i]; e; e = e->next) {
342            xc_fillentry_dmz(e, 0, list TSRMLS_CC);
343        }
344    }
345    add_assoc_zval(return_value, "cache_list", list);
346
347    ALLOC_INIT_ZVAL(list);
348    array_init(list);
349    for (e = cache->deletes; e; e = e->next) {
350        xc_fillentry_dmz(e, 1, list TSRMLS_CC);
351    }
352    add_assoc_zval(return_value, "deleted_list", list);
353}
354/* }}} */
355
356static zend_op_array *xc_entry_install(xc_entry_t *xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
357{
358    zend_uint i;
359    xc_entry_data_php_t *p = xce->data.php;
360#ifndef ZEND_ENGINE_2
361    /* new ptr which is stored inside CG(class_table) */
362    xc_cest_t **new_cest_ptrs = (xc_cest_t **)do_alloca(sizeof(xc_cest_t*) * p->classinfo_cnt);
363#endif
364
365    /* install function */
366    for (i = 0; i < p->funcinfo_cnt; i ++) {
367        xc_funcinfo_t  *fi = &p->funcinfos[i];
368        xc_install_function(xce->name.str.val, &fi->func,
369                UNISW(0, fi->type), fi->key, fi->key_size TSRMLS_CC);
370    }
371
372    /* install class */
373    for (i = 0; i < p->classinfo_cnt; i ++) {
374        xc_classinfo_t *ci = &p->classinfos[i];
375#ifndef ZEND_ENGINE_2
376        zend_class_entry *ce = CestToCePtr(ci->cest);
377        /* fix pointer to the be which inside class_table */
378        if (ce->parent) {
379            zend_uint class_idx = (/* class_num */ (int) ce->parent) - 1;
380            assert(class_idx < i);
381            ci->cest.parent = new_cest_ptrs[class_idx];
382        }
383        new_cest_ptrs[i] =
384#endif
385        xc_install_class(xce->name.str.val, &ci->cest,
386                UNISW(0, ci->type), ci->key, ci->key_size TSRMLS_CC);
387    }
388
389    i = 1;
390    zend_hash_add(&EG(included_files), xce->name.str.val, xce->name.str.len+1, (void *)&i, sizeof(int), NULL);
391    zend_llist_add_element(&CG(open_files), h);
392
393#ifndef ZEND_ENGINE_2
394    free_alloca(new_cest_ptrs);
395#endif
396    return p->op_array;
397}
398/* }}} */
399static void xc_entry_gc_real(xc_cache_t **caches, int size TSRMLS_DC) /* {{{ */
400{
401    time_t t = XG(request_time);
402    int i;
403    xc_cache_t *cache;
404    typedef xc_entry_t *xc_delete_t;
405    xc_delete_t p, *last;
406
407    for (i = 0; i < size; i ++) {
408        cache = caches[i];
409        ENTER_LOCK(cache) {
410            if (cache->deletes) {
411                last = (xc_delete_t *) &cache->deletes;
412                for (p = *last; p; p = p->next) {
413                    if (t - p->dtime > 3600) {
414                        p->refcount = 0;
415                        /* issue warning here */
416                    }
417                    if (p->refcount == 0) {
418                        *last = p->next;
419                        xc_entry_free_dmz(p);
420                    }
421                    else {
422                        last = &(p->next);
423                    }
424                }
425            }
426        } LEAVE_LOCK(cache);
427    }
428}
429/* }}} */
430static void xc_entry_gc(TSRMLS_D) /* {{{ */
431{
432    xc_entry_gc_real(xc_php_caches, xc_php_hcache.size TSRMLS_CC);
433    xc_entry_gc_real(xc_var_caches, xc_var_hcache.size TSRMLS_CC);
434}
435/* }}} */
436static inline void xc_entry_unholds_real(xc_stack_t *holds, xc_cache_t **caches, int cachecount TSRMLS_DC) /* {{{ */
437{
438    int i;
439    xc_stack_t *s;
440    xc_cache_t *cache;
441    xc_entry_t *xce;
442
443    for (i = 0; i < cachecount; i ++) {
444        s = &holds[i];
445        if (xc_stack_size(s)) {
446            cache = ((xc_entry_t *)xc_stack_top(s))->cache;
447            ENTER_LOCK(cache) {
448                while (xc_stack_size(holds)) {
449                    xce = (xc_entry_t*) xc_stack_pop(holds);
450                    xce->refcount --;
451                    assert(xce->refcount >= 0);
452                }
453            } LEAVE_LOCK(cache);
454        }
455    }
456}
457/* }}} */
458static void xc_entry_unholds(TSRMLS_D) /* {{{ */
459{
460    xc_entry_unholds_real(XG(php_holds), xc_php_caches, xc_php_hcache.size TSRMLS_CC);
461    xc_entry_unholds_real(XG(var_holds), xc_var_caches, xc_var_hcache.size TSRMLS_CC);
462}
463/* }}} */
464static int xc_stat(const char *filename, const char *include_path, struct stat *pbuf TSRMLS_DC) /* {{{ */
465{
466    char filepath[1024];
467    char *paths, *path;
468    char *tokbuf;
469    int size = strlen(include_path) + 1;
470    char tokens[] = { DEFAULT_DIR_SEPARATOR, '\0' };
471
472    paths = (char *)do_alloca(size);
473    memcpy(paths, include_path, size);
474
475    for (path = php_strtok_r(paths, tokens, &tokbuf); path; path = php_strtok_r(NULL, tokens, &tokbuf)) {
476        if (strlen(path) + strlen(filename) + 1 > 1024) {
477            continue;
478        }
479        snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
480        if (VCWD_STAT(filepath, pbuf) == 0) {
481            free_alloca(paths);
482            return 0;
483        }
484    }
485
486    free_alloca(paths);
487
488    return 1;
489}
490/* }}} */
491
492#define HASH(i) (i)
493#define HASH_USTR_L(t, s, l) HASH(zend_u_inline_hash_func(t, s, (l + 1) * sizeof(UChar)))
494#define HASH_STR_L(s, l) HASH(zend_inline_hash_func(s, l + 1))
495#define HASH_STR(s) HASH_STR_L(s, strlen(s) + 1)
496#define HASH_NUM(n) HASH(n)
497static inline xc_hash_value_t xc_entry_hash_var(xc_entry_t *xce) /* {{{ */
498{
499    return UNISW(, UG(unicode) ? HASH_USTR_L(xce->name_type, (char *)xce->name.ustr.val, xce->name.ustr.len) :)
500        HASH_STR_L(xce->name.str.val, xce->name.str.len);
501}
502/* }}} */
503static inline xc_hash_value_t xc_entry_hash_php(xc_entry_t *xce) /* {{{ */
504{
505#ifdef HAVE_INODE
506    return HASH(xce->data.php->device + xce->data.php->inode);
507#else
508    return xc_entry_hash_var(xce);
509#endif
510}
511/* }}} */
512static int xc_entry_init_key_php(xc_entry_t *xce, char *filename TSRMLS_DC) /* {{{ */
513{
514    struct stat buf, *pbuf;
515    xc_hash_value_t hv;
516    int cacheid;
517    xc_entry_data_php_t *php;
518
519    if (!filename || !SG(request_info).path_translated) {
520        return 0;
521    }
522
523    do {
524        if (strcmp(SG(request_info).path_translated, filename) == 0) {
525            /* sapi has already done this stat() for us */
526            pbuf = sapi_get_stat(TSRMLS_C);
527            if (pbuf) {
528                break;
529            }
530        }
531
532        pbuf = &buf;
533        if (IS_ABSOLUTE_PATH(filename, strlen(filename))) {
534            if (VCWD_STAT(filename, pbuf) != 0) {
535                return 0;
536            }
537        }
538        else {
539            if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != 0) {   
540                return 0;
541            }
542        }
543    } while (0);
544
545    if (XG(request_time) - pbuf->st_mtime < 2) {
546        return 0;
547    }
548
549    UNISW(, xce->name_type = IS_STRING;)
550    xce->name.str.val = filename;
551    xce->name.str.len = strlen(filename);
552
553    php = xce->data.php;
554    php->mtime        = pbuf->st_mtime;
555#ifdef HAVE_INODE
556    php->device       = pbuf->st_dev;
557    php->inode        = pbuf->st_ino;
558#endif
559    php->sourcesize   = pbuf->st_size;
560
561
562    hv = xc_entry_hash_php(xce);
563    cacheid = (hv & xc_php_hcache.mask);
564    xce->cache = xc_php_caches[cacheid];
565    hv >>= xc_php_hcache.bits;
566    xce->hvalue = (hv & xc_php_hentry.mask);
567
568    xce->type = XC_TYPE_PHP;
569    return 1;
570}
571/* }}} */
572static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
573{
574    xc_sandbox_t sandbox;
575    zend_op_array *op_array;
576    xc_entry_t xce, *stored_xce;
577    xc_entry_data_php_t php;
578    xc_cache_t *cache;
579    zend_bool clogged = 0;
580    zend_bool catched = 0;
581    char *filename;
582
583    if (!xc_initized) {
584        assert(0);
585    }
586
587    if (!XG(cacher)) {
588        op_array = origin_compile_file(h, type TSRMLS_CC);
589#ifdef HAVE_XCACHE_OPTIMIZER
590        if (XG(optimizer)) {
591            xc_optimize(op_array TSRMLS_CC);
592        }
593#endif
594        return op_array;
595    }
596
597    /* {{{ prepare key
598     * include_once() and require_once() gives us opened_path
599     * however, include() and require() non-absolute path which break
600     * included_files, and may confuse with (include|require)_once
601     * -- Xuefer
602     */
603
604    filename = h->opened_path ? h->opened_path : h->filename;
605    xce.data.php = &php;
606    if (!xc_entry_init_key_php(&xce, filename TSRMLS_CC)) {
607        return origin_compile_file(h, type TSRMLS_CC);
608    }
609    cache = xce.cache;
610    /* }}} */
611    /* {{{ restore */
612    /* stale precheck */
613    if (cache->compiling) {
614        cache->clogs ++; /* is it safe here? */
615        return origin_compile_file(h, type TSRMLS_CC);
616    }
617
618    stored_xce = NULL;
619    op_array = NULL;
620    ENTER_LOCK(cache) {
621        /* clogged */
622        if (cache->compiling) {
623            cache->clogs ++;
624            op_array = NULL;
625            clogged = 1;
626            break;
627        }
628
629        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
630        /* found */
631        if (stored_xce) {
632#ifdef DEBUG
633            fprintf(stderr, "found %s, catch it\n", stored_xce->name.str.val);
634#endif
635            xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
636            cache->hits ++;
637            break;
638        }
639
640        cache->compiling = XG(request_time);
641        cache->misses ++;
642    } LEAVE_LOCK(cache);
643
644    /* found */
645    if (stored_xce) {
646        goto restore;
647    }
648
649    /* clogged */
650    if (clogged) {
651        return origin_compile_file(h, type TSRMLS_CC);
652    }
653    /* }}} */
654
655    /* {{{ compile */
656#ifdef DEBUG
657    fprintf(stderr, "compiling %s\n", filename);
658#endif
659
660    /* make compile inside sandbox */
661    xc_sandbox_init(&sandbox, filename TSRMLS_CC);
662
663    zend_try {
664        op_array = origin_compile_file(h, type TSRMLS_CC);
665    } zend_catch {
666        catched = 1;
667    } zend_end_try();
668
669    if (catched) {
670        goto err_bailout;
671    }
672
673    if (op_array == NULL) {
674        goto err_oparray;
675    }
676
677#ifdef HAVE_XCACHE_OPTIMIZER
678    if (XG(optimizer)) {
679        xc_optimize(op_array TSRMLS_CC);
680    }
681#endif
682
683    php.op_array      = op_array;
684
685    php.funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
686    php.classinfo_cnt = zend_hash_num_elements(CG(class_table));
687
688    php.funcinfos     = ECALLOC_N(php.funcinfos, php.funcinfo_cnt);
689    if (!php.funcinfos) {
690        goto err_func;
691    }
692    php.classinfos    = ECALLOC_N(php.classinfos, php.classinfo_cnt);
693    if (!php.classinfos) {
694        goto err_class;
695    }
696    /* }}} */
697    /* {{{ shallow copy, pointers only */ {
698        Bucket *b;
699        unsigned int i;
700
701        b = CG(function_table)->pListHead;
702        for (i = 0; b; i ++, b = b->pListNext) {
703            xc_funcinfo_t *fi = &php.funcinfos[i];
704
705            assert(i < php.funcinfo_cnt);
706            assert(b->pData);
707            memcpy(&fi->func, b->pData, sizeof(zend_function));
708            UNISW(, fi->type = b->key.type;)
709            fi->key        = BUCKET_KEY(b);
710            fi->key_size   = b->nKeyLength;
711        }
712
713        b = CG(class_table)->pListHead;
714        for (i = 0; b; i ++, b = b->pListNext) {
715            xc_classinfo_t *ci = &php.classinfos[i];
716
717            assert(i < php.classinfo_cnt);
718            assert(b->pData);
719            memcpy(&ci->cest, b->pData, sizeof(xc_cest_t));
720            UNISW(, ci->type = b->key.type;)
721            ci->key        = BUCKET_KEY(b);
722            ci->key_size   = b->nKeyLength;
723            /* need to fix inside store */
724        }
725    }
726    /* }}} */
727    xc_entry_gc(TSRMLS_C);
728    ENTER_LOCK(cache) { /* {{{ store/add entry */
729        stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
730    } LEAVE_LOCK(cache);
731    /* }}} */
732#ifdef DEBUG
733    fprintf(stderr, "stored\n");
734#endif
735
736    efree(xce.data.php->classinfos);
737err_class:
738    efree(xce.data.php->funcinfos);
739err_func:
740err_oparray:
741err_bailout:
742
743    if (xc_test && stored_xce) {
744        /* no install, keep open_files too for h */
745        xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
746        sandbox.tmp_open_files->dtor = NULL;
747    }
748    else {
749        xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
750    }
751
752    ENTER_LOCK(cache) {
753        cache->compiling = 0;
754    } LEAVE_LOCK(cache);
755    if (catched) {
756        zend_bailout();
757    }
758    if (xc_test && stored_xce) {
759        goto restore;
760    }
761    return op_array;
762
763restore:
764#ifdef DEBUG
765    fprintf(stderr, "restoring\n");
766#endif
767    xc_processor_restore_xc_entry_t(&xce, stored_xce, xc_readonly_protection TSRMLS_CC);
768    op_array = xc_entry_install(&xce, h TSRMLS_CC);
769
770    efree(xce.data.php->funcinfos);
771    efree(xce.data.php->classinfos);
772    efree(xce.data.php);
773#ifdef DEBUG
774    fprintf(stderr, "restored\n");
775#endif
776    return op_array;
777}
778/* }}} */
779
780/* gdb helper functions, but N/A for coredump */
781int xc_is_rw(const void *p) /* {{{ */
782{
783    int i;
784    if (!xc_initized) {
785        return 0;
786    }
787    for (i = 0; i < xc_php_hcache.size; i ++) {
788        if (xc_shm_is_readwrite(xc_php_caches[i]->shm, p)) {
789            return 1;
790        }
791    }
792    for (i = 0; i < xc_var_hcache.size; i ++) {
793        if (xc_shm_is_readwrite(xc_var_caches[i]->shm, p)) {
794            return 1;
795        }
796    }
797    return 0;
798}
799/* }}} */
800int xc_is_ro(const void *p) /* {{{ */
801{
802    int i;
803    if (!xc_initized) {
804        return 0;
805    }
806    for (i = 0; i < xc_php_hcache.size; i ++) {
807        if (xc_shm_is_readonly(xc_php_caches[i]->shm, p)) {
808            return 1;
809        }
810    }
811    for (i = 0; i < xc_var_hcache.size; i ++) {
812        if (xc_shm_is_readonly(xc_var_caches[i]->shm, p)) {
813            return 1;
814        }
815    }
816    return 0;
817}
818/* }}} */
819int xc_is_shm(const void *p) /* {{{ */
820{
821    return xc_is_ro(p) || xc_is_rw(p);
822}
823/* }}} */
824
825/* module helper function */
826static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
827{
828    typedef struct {
829        const char *prefix;
830        int (*getsize)();
831        const char *(*get)(zend_uchar i);
832    } xc_meminfo_t;
833    xc_meminfo_t nameinfos[] = {
834        { "",        xc_get_op_type_count,   xc_get_op_type   },
835        { "",        xc_get_data_type_count, xc_get_data_type },
836        { "",        xc_get_opcode_count,    xc_get_opcode    },
837        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
838        { NULL, NULL, NULL }
839    };
840    xc_meminfo_t* p;
841    int i;
842    char const_name[96];
843    int const_name_len;
844    int undefdone = 0;
845
846    for (p = nameinfos; p->getsize; p ++) {
847        for (i = p->getsize() - 1; i >= 0; i --) {
848            const char *name = p->get(i);
849            if (!name) continue;
850            if (strcmp(name, "UNDEF") == 0) {
851                if (undefdone) continue;
852                undefdone = 1;
853            }
854            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
855            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
856        }
857    }
858
859    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
860    zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
861    zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
862    return 0;
863}
864/* }}} */
865static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
866{
867    int i;
868    xc_cache_t *cache;
869    xc_shm_t *shm;
870
871    if (!caches) {
872        return NULL;
873    }
874    shm = NULL;
875    for (i = 0; i < hcache->size; i ++) {
876        cache = caches[i];
877        if (cache) {
878            if (cache->lck) {
879                xc_lock_destroy(cache->lck);
880            }
881            /* do NOT free
882            if (cache->entries) {
883                xc_mem_free(cache->mem, cache->entries);
884            }
885            xc_mem_free(cache->mem, cache);
886            */
887            xc_mem_destroy(cache->mem);
888            shm = cache->shm;
889        }
890    }
891    free(caches);
892    return shm;
893}
894/* }}} */
895static xc_cache_t **xc_cache_init(xc_shm_t *shm, char *ptr, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */
896{
897    xc_cache_t **caches = NULL, *cache;
898    xc_mem_t *mem;
899    int i;
900
901    xc_memsize_t memsize = shmsize / hcache->size;
902
903    CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
904
905    for (i = 0; i < hcache->size; i ++) {
906        mem = xc_mem_init(ptr, memsize);
907        ptr += ALIGN(memsize);
908        CHECK(cache          = xc_mem_calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
909        CHECK(cache->entries = xc_mem_calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
910        CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
911
912        cache->hcache  = hcache;
913        cache->hentry  = hentry;
914        cache->shm     = shm;
915        cache->mem     = mem;
916        cache->cacheid = i;
917        caches[i] = cache;
918    }
919    assert(ptr <= (char*)xc_shm_ptr(shm) + shmsize);
920    return caches;
921
922err:
923    if (caches) {
924        xc_cache_destroy(caches, hcache);
925    }
926    return NULL;
927}
928/* }}} */
929static void xc_destroy() /* {{{ */
930{
931    xc_shm_t *shm = NULL;
932
933    if (origin_compile_file) {
934        zend_compile_file = origin_compile_file;
935        origin_compile_file = NULL;
936    }
937
938    if (xc_php_caches) {
939        shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
940        xc_php_caches = NULL;
941    }
942    if (xc_var_caches) {
943        shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
944        xc_var_caches = NULL;
945    }
946    if (shm) {
947        xc_shm_destroy(shm);
948    }
949}
950/* }}} */
951static int xc_init(int module_number TSRMLS_DC) /* {{{ */
952{
953    xc_shm_t *shm;
954    char *ptr;
955
956    xc_php_caches = xc_var_caches = NULL;
957
958    if (xc_php_size || xc_var_size) {
959        CHECK(shm = xc_shm_init(xc_mmap_path, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection), "Cannot create shm");
960        if (!xc_shm_can_readonly(shm)) {
961            xc_readonly_protection = 0;
962        }
963
964        ptr = (char *)xc_shm_ptr(shm);
965        if (xc_php_size) {
966            origin_compile_file = zend_compile_file;
967            zend_compile_file = xc_compile_file;
968
969            CHECK(xc_php_caches = xc_cache_init(shm, ptr, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
970            ptr += ALIGN(xc_php_size);
971        }
972
973        if (xc_var_size) {
974            CHECK(xc_var_caches = xc_cache_init(shm, ptr, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache");
975        }
976    }
977    return 1;
978
979err:
980    if (xc_php_caches || xc_var_caches) {
981        xc_destroy();
982        /* shm destroied */
983    }
984    else if (shm) {
985        xc_shm_destroy(shm);
986    }
987    return 0;
988}
989/* }}} */
990static void xc_request_init(TSRMLS_D) /* {{{ */
991{
992    int i;
993
994    if (xc_php_hcache.size && !XG(php_holds)) {
995        XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
996        for (i = 0; i < xc_php_hcache.size; i ++) {
997            xc_stack_init(&XG(php_holds[i]));
998        }
999    }
1000
1001    if (xc_var_hcache.size && !XG(var_holds)) {
1002        XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
1003        for (i = 0; i < xc_var_hcache.size; i ++) {
1004            xc_stack_init(&XG(var_holds[i]));
1005        }
1006    }
1007
1008    if (XG(cacher)) {
1009#if PHP_API_VERSION <= 20041225
1010        XG(request_time) = time(NULL);
1011#else
1012        XG(request_time) = sapi_get_request_time(TSRMLS_C);
1013#endif
1014    }
1015#ifdef HAVE_XCACHE_COVERAGE
1016    xc_coverage_request_init(TSRMLS_C);
1017#endif
1018}
1019/* }}} */
1020static void xc_request_shutdown(TSRMLS_D) /* {{{ */
1021{
1022    xc_entry_unholds(TSRMLS_C);
1023#ifdef HAVE_XCACHE_COVERAGE
1024    xc_coverage_request_shutdown(TSRMLS_C);
1025#endif
1026}
1027/* }}} */
1028static void xc_init_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
1029{
1030    memset(xc_globals, 0, sizeof(zend_xcache_globals));
1031}
1032/* }}} */
1033static void xc_shutdown_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
1034{
1035    int i;
1036
1037    if (xc_globals->php_holds != NULL) {
1038        for (i = 0; i < xc_php_hcache.size; i ++) {
1039            xc_stack_destroy(&xc_globals->php_holds[i]);
1040        }
1041        free(xc_globals->php_holds);
1042        xc_globals->php_holds = NULL;
1043    }
1044
1045    if (xc_globals->var_holds != NULL) {
1046        for (i = 0; i < xc_var_hcache.size; i ++) {
1047            xc_stack_destroy(&xc_globals->var_holds[i]);
1048        }
1049        free(xc_globals->var_holds);
1050        xc_globals->var_holds = NULL;
1051    }
1052}
1053/* }}} */
1054
1055/* user functions */
1056/* {{{ xcache_op */
1057typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
1058static void xcache_op(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
1059{
1060    long type;
1061    int size;
1062    xc_cache_t **caches, *cache;
1063    long id = 0;
1064
1065    if (!xc_initized) {
1066        php_error_docref(NULL TSRMLS_CC, E_WARNING, "XCache is not initized");
1067        RETURN_FALSE;
1068    }
1069
1070    if (optype == XC_OP_COUNT) {
1071        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
1072            return;
1073        }
1074    }
1075    else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
1076        return;
1077    }
1078
1079    switch (type) {
1080        case XC_TYPE_PHP:
1081            size = xc_php_hcache.size;
1082            caches = xc_php_caches;
1083            break;
1084
1085        case XC_TYPE_VAR:
1086            size = xc_var_hcache.size;
1087            caches = xc_var_caches;
1088            break;
1089
1090        default:
1091            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
1092            RETURN_FALSE;
1093    }
1094
1095    switch (optype) {
1096        case XC_OP_COUNT:
1097            RETURN_LONG(size)
1098            break;
1099
1100        case XC_OP_INFO:
1101        case XC_OP_LIST:
1102            if (id < 0 || id >= size) {
1103                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1104                RETURN_FALSE;
1105            }
1106
1107            array_init(return_value);
1108
1109            cache = caches[id];
1110            ENTER_LOCK(cache) {
1111                if (optype == XC_OP_INFO) {
1112                    xc_fillinfo_dmz(cache, return_value TSRMLS_CC);
1113                }
1114                else {
1115                    xc_filllist_dmz(cache, return_value TSRMLS_CC);
1116                }
1117            } LEAVE_LOCK(cache);
1118            break;
1119        case XC_OP_CLEAR:
1120            {
1121                xc_entry_t *e;
1122                int i, c;
1123
1124                if (id < 0 || id >= size) {
1125                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1126                    RETURN_FALSE;
1127                }
1128
1129                cache = caches[id];
1130                ENTER_LOCK(cache) {
1131                    for (i = 0, c = cache->hentry->size; i < c; i ++) {
1132                        for (e = cache->entries[i]; e; e = e->next) {
1133                            xc_entry_remove_dmz(e TSRMLS_CC);
1134                        }
1135                        cache->entries[i] = NULL;
1136                    }
1137                } LEAVE_LOCK(cache);
1138                xc_entry_gc(TSRMLS_C);
1139            }
1140            break;
1141
1142        default:
1143            assert(0);
1144    }
1145}
1146/* }}} */
1147/* {{{ proto int xcache_count(int type)
1148   Return count of cache on specified cache type */
1149PHP_FUNCTION(xcache_count)
1150{
1151    xcache_op(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1152}
1153/* }}} */
1154/* {{{ proto array xcache_info(int type, int id)
1155   Get cache info by id on specified cache type */
1156PHP_FUNCTION(xcache_info)
1157{
1158    xcache_op(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1159}
1160/* }}} */
1161/* {{{ proto array xcache_list(int type, int id)
1162   Get cache entries list by id on specified cache type */
1163PHP_FUNCTION(xcache_list)
1164{
1165    xcache_op(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1166}
1167/* }}} */
1168/* {{{ proto array xcache_clear_cache(int type, int id)
1169   Clear cache by id on specified cache type */
1170PHP_FUNCTION(xcache_clear_cache)
1171{
1172    xcache_op(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1173}
1174/* }}} */
1175
1176static int xc_entry_init_key_var(xc_entry_t *xce, zval *name TSRMLS_DC) /* {{{ */
1177{
1178    xc_hash_value_t hv;
1179    int cacheid;
1180
1181    switch (Z_TYPE_P(name)) {
1182#ifdef IS_UNICODE
1183        case IS_UNICODE:
1184#endif
1185        case IS_STRING:
1186            break;
1187        default:
1188#ifdef IS_UNICODE
1189            convert_to_text(name);
1190#else
1191            convert_to_string(name);
1192#endif
1193    }
1194#ifdef IS_UNICODE
1195    xce->name_type = name->type;
1196#endif
1197    xce->name = name->value;
1198
1199    hv = xc_entry_hash_var(xce);
1200
1201    cacheid = (hv & xc_var_hcache.mask);
1202    xce->cache = xc_var_caches[cacheid];
1203    hv >>= xc_var_hcache.bits;
1204    xce->hvalue = (hv & xc_var_hentry.mask);
1205
1206    xce->type = XC_TYPE_VAR;
1207    return SUCCESS;
1208}
1209/* }}} */
1210#define TIME_MAX (sizeof(time_t) == sizeof(long) ? LONG_MAX : INT_MAX)
1211/* {{{ proto mixed xcache_get(string name)
1212   Get cached data by specified name */
1213PHP_FUNCTION(xcache_get)
1214{
1215    xc_entry_t xce, *stored_xce;
1216    xc_entry_data_var_t var;
1217    zval *name;
1218
1219    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1220        return;
1221    }
1222    xce.data.var = &var;
1223    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1224
1225    ENTER_LOCK(xce.cache) {
1226        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1227        if (stored_xce) {
1228            if (XG(request_time) <= stored_xce->data.var->etime) {
1229                xc_processor_restore_zval(return_value, stored_xce->data.var->value TSRMLS_CC);
1230                /* return */
1231                break;
1232            }
1233            else {
1234                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1235            }
1236        }
1237
1238        RETVAL_NULL();
1239    } LEAVE_LOCK(xce.cache);
1240}
1241/* }}} */
1242/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
1243   Store data to cache by specified name */
1244PHP_FUNCTION(xcache_set)
1245{
1246    xc_entry_t xce, *stored_xce;
1247    xc_entry_data_var_t var;
1248    zval *name;
1249    zval *value;
1250    long ttl = 0;
1251
1252    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &ttl) == FAILURE) {
1253        return;
1254    }
1255    xce.data.var = &var;
1256    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1257
1258    ENTER_LOCK(xce.cache) {
1259        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1260        if (stored_xce) {
1261            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1262        }
1263        var.value = value;
1264        var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
1265        RETVAL_BOOL(xc_entry_store_dmz(&xce TSRMLS_CC) != NULL ? 1 : 0);
1266    } LEAVE_LOCK(xce.cache);
1267}
1268/* }}} */
1269/* {{{ proto bool  xcache_isset(string name)
1270   Check if an entry exists in cache by specified name */
1271PHP_FUNCTION(xcache_isset)
1272{
1273    xc_entry_t xce, *stored_xce;
1274    xc_entry_data_var_t var;
1275    zval *name;
1276
1277    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1278        return;
1279    }
1280    xce.data.var = &var;
1281    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1282
1283    ENTER_LOCK(xce.cache) {
1284        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1285        if (stored_xce) {
1286            if (XG(request_time) <= stored_xce->data.var->etime) {
1287                RETVAL_TRUE;
1288                /* return */
1289                break;
1290            }
1291            else {
1292                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1293            }
1294        }
1295
1296        RETVAL_FALSE;
1297    } LEAVE_LOCK(xce.cache);
1298}
1299/* }}} */
1300/* {{{ proto bool  xcache_unset(string name)
1301   Unset existing data in cache by specified name */
1302PHP_FUNCTION(xcache_unset)
1303{
1304    xc_entry_t xce, *stored_xce;
1305    xc_entry_data_var_t var;
1306    zval *name;
1307
1308    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1309        return;
1310    }
1311    xce.data.var = &var;
1312    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1313
1314    ENTER_LOCK(xce.cache) {
1315        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1316        if (stored_xce) {
1317            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1318            RETVAL_TRUE;
1319        }
1320        else {
1321            RETVAL_FALSE;
1322        }
1323    } LEAVE_LOCK(xce.cache);
1324}
1325/* }}} */
1326static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
1327{
1328    xc_entry_t xce, *stored_xce;
1329    xc_entry_data_var_t var, *stored_var;
1330    zval *name;
1331    long count = 1;
1332    long ttl = 0;
1333    long value = 0;
1334    zval oldzval;
1335
1336    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &ttl) == FAILURE) {
1337        return;
1338    }
1339    xce.data.var = &var;
1340    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1341
1342    ENTER_LOCK(xce.cache) {
1343        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1344        if (stored_xce) {
1345#ifdef DEBUG
1346            fprintf(stderr, "incdec: gotxce %s\n", xce.name.str.val);
1347#endif
1348            stored_var = stored_xce->data.var;
1349            /* timeout */
1350            if (XG(request_time) > stored_var->etime) {
1351#ifdef DEBUG
1352                fprintf(stderr, "incdec: expired\n");
1353#endif
1354                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1355                stored_xce = NULL;
1356            }
1357            else {
1358                /* do it in place */
1359                if (Z_TYPE_P(stored_var->value) == IS_LONG) {
1360#ifdef DEBUG
1361                    fprintf(stderr, "incdec: islong\n");
1362#endif
1363                    value = Z_LVAL_P(stored_var->value);
1364                    value += (inc == 1 ? count : - count);
1365                    RETVAL_LONG(value);
1366                    Z_LVAL_P(stored_var->value) = value;
1367                    break;
1368                }
1369                else {
1370#ifdef DEBUG
1371                    fprintf(stderr, "incdec: notlong\n");
1372#endif
1373                    xc_processor_restore_zval(&oldzval, stored_xce->data.var->value TSRMLS_CC);
1374                    convert_to_long(&oldzval);
1375                    value = Z_LVAL(oldzval);
1376                    zval_dtor(&oldzval);
1377                }
1378            }
1379        }
1380#ifdef DEBUG
1381        else {
1382            fprintf(stderr, "incdec: %s not found\n", xce.name.str.val);
1383        }
1384#endif
1385
1386        value += (inc == 1 ? count : - count);
1387        RETVAL_LONG(value);
1388        var.value = return_value;
1389        var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
1390        if (stored_xce) {
1391            xce.atime = stored_xce->atime;
1392            xce.ctime = stored_xce->ctime;
1393            xce.hits  = stored_xce->hits;
1394            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1395        }
1396        xc_entry_store_dmz(&xce TSRMLS_CC);
1397
1398    } LEAVE_LOCK(xce.cache);
1399}
1400/* }}} */
1401/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
1402   Increase an int counter in cache by specified name, create it if not exists */
1403PHP_FUNCTION(xcache_inc)
1404{
1405    xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1406}
1407/* }}} */
1408/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
1409   Decrease an int counter in cache by specified name, create it if not exists */
1410PHP_FUNCTION(xcache_dec)
1411{
1412    xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1413}
1414/* }}} */
1415/* {{{ proto string xcache_asm(string filename)
1416 */
1417#ifdef HAVE_XCACHE_ASSEMBLER
1418PHP_FUNCTION(xcache_asm)
1419{
1420}
1421#endif
1422/* }}} */
1423#ifdef HAVE_XCACHE_DISASSEMBLER
1424/* {{{ proto array  xcache_dasm_file(string filename)
1425   Disassemble file into opcode array by filename */
1426PHP_FUNCTION(xcache_dasm_file)
1427{
1428    char *filename;
1429    long filename_len;
1430
1431    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1432        return;
1433    }
1434    if (!filename_len) RETURN_FALSE;
1435
1436    xc_dasm_file(return_value, filename TSRMLS_CC);
1437}
1438/* }}} */
1439/* {{{ proto array  xcache_dasm_string(string code)
1440   Disassemble php code into opcode array */
1441PHP_FUNCTION(xcache_dasm_string)
1442{
1443    zval *code;
1444
1445    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
1446        return;
1447    }
1448    xc_dasm_string(return_value, code TSRMLS_CC);
1449}
1450/* }}} */
1451#endif
1452/* {{{ proto string xcache_encode(string filename)
1453   Encode php file into XCache opcode encoded format */
1454#ifdef HAVE_XCACHE_ENCODER
1455PHP_FUNCTION(xcache_encode)
1456{
1457}
1458#endif
1459/* }}} */
1460/* {{{ proto bool xcache_decode_file(string filename)
1461   Decode(load) opcode from XCache encoded format file */
1462#ifdef HAVE_XCACHE_DECODER
1463PHP_FUNCTION(xcache_decode_file)
1464{
1465}
1466#endif
1467/* }}} */
1468/* {{{ proto bool xcache_decode_string(string data)
1469   Decode(load) opcode from XCache encoded format data */
1470#ifdef HAVE_XCACHE_DECODER
1471PHP_FUNCTION(xcache_decode_string)
1472{
1473}
1474#endif
1475/* }}} */
1476/* {{{ xc_call_getter */
1477typedef const char *(xc_name_getter_t)(zend_uchar type);
1478static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
1479{
1480    long spec;
1481    const char *name;
1482
1483    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1484        return;
1485    }
1486    if (spec >= 0 && spec < count) {
1487        name = getter((zend_uchar) spec);
1488        if (name) {
1489            /* RETURN_STRING */
1490            int len = strlen(name);
1491            return_value->value.str.len = len;
1492            return_value->value.str.val = estrndup(name, len);
1493            return_value->type = IS_STRING; 
1494            return;
1495        }
1496    }
1497    RETURN_NULL();
1498}
1499/* }}} */
1500/* {{{ proto string xcache_get_op_type(int op_type) */
1501PHP_FUNCTION(xcache_get_op_type)
1502{
1503    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1504}
1505/* }}} */
1506/* {{{ proto string xcache_get_data_type(int type) */
1507PHP_FUNCTION(xcache_get_data_type)
1508{
1509    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1510}
1511/* }}} */
1512/* {{{ proto string xcache_get_opcode(int opcode) */
1513PHP_FUNCTION(xcache_get_opcode)
1514{
1515    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1516}
1517/* }}} */
1518/* {{{ proto string xcache_get_op_spec(int op_type) */
1519PHP_FUNCTION(xcache_get_op_spec)
1520{
1521    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1522}
1523/* }}} */
1524#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
1525/* {{{ proto string xcache_get_opcode_spec(int opcode) */
1526PHP_FUNCTION(xcache_get_opcode_spec)
1527{
1528    long spec;
1529    const xc_opcode_spec_t *opspec;
1530
1531    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1532        return;
1533    }
1534    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
1535        opspec = xc_get_opcode_spec((zend_uchar) spec);
1536        if (opspec) {
1537            array_init(return_value);
1538            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
1539            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
1540            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
1541            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
1542            return;
1543        }
1544    }
1545    RETURN_NULL();
1546}
1547/* }}} */
1548#endif
1549/* {{{ proto mixed xcache_get_special_value(zval value) */
1550PHP_FUNCTION(xcache_get_special_value)
1551{
1552    zval *value;
1553
1554    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
1555        return;
1556    }
1557
1558    if (value->type == IS_CONSTANT) {
1559        *return_value = *value;
1560        zval_copy_ctor(return_value);
1561        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
1562        return;
1563    }
1564
1565    if (value->type == IS_CONSTANT_ARRAY) {
1566        *return_value = *value;
1567        zval_copy_ctor(return_value);
1568        return_value->type = IS_ARRAY;
1569        return;
1570    }
1571
1572    RETURN_NULL();
1573}
1574/* }}} */
1575/* {{{ proto string xcache_coredump(int op_type) */
1576PHP_FUNCTION(xcache_coredump)
1577{
1578    if (xc_test) {
1579        raise(SIGSEGV);
1580    }
1581    else {
1582        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
1583    }
1584}
1585/* }}} */
1586/* {{{ proto string xcache_is_autoglobal(string name) */
1587PHP_FUNCTION(xcache_is_autoglobal)
1588{
1589    char *name;
1590    long name_len;
1591
1592    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
1593        return;
1594    }
1595
1596    RETURN_BOOL(zend_hash_exists(CG(auto_globals), name, name_len + 1));
1597}
1598/* }}} */
1599static function_entry xcache_functions[] = /* {{{ */
1600{
1601    PHP_FE(xcache_count,             NULL)
1602    PHP_FE(xcache_info,              NULL)
1603    PHP_FE(xcache_list,              NULL)
1604    PHP_FE(xcache_clear_cache,       NULL)
1605    PHP_FE(xcache_coredump,          NULL)
1606#ifdef HAVE_XCACHE_ASSEMBLER
1607    PHP_FE(xcache_asm,               NULL)
1608#endif
1609#ifdef HAVE_XCACHE_DISASSEMBLER
1610    PHP_FE(xcache_dasm_file,         NULL)
1611    PHP_FE(xcache_dasm_string,       NULL)
1612#endif
1613#ifdef HAVE_XCACHE_ENCODER
1614    PHP_FE(xcache_encode,            NULL)
1615#endif
1616#ifdef HAVE_XCACHE_DECODER
1617    PHP_FE(xcache_decode_file,       NULL)
1618    PHP_FE(xcache_decode_string,     NULL)
1619#endif
1620#ifdef HAVE_XCACHE_COVERAGE
1621    PHP_FE(xcache_coverage_decode,   NULL)
1622#endif
1623    PHP_FE(xcache_get_special_value, NULL)
1624    PHP_FE(xcache_get_op_type,       NULL)
1625    PHP_FE(xcache_get_data_type,     NULL)
1626    PHP_FE(xcache_get_opcode,        NULL)
1627#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
1628    PHP_FE(xcache_get_opcode_spec,   NULL)
1629#endif
1630    PHP_FE(xcache_is_autoglobal,     NULL)
1631    PHP_FE(xcache_inc,               NULL)
1632    PHP_FE(xcache_dec,               NULL)
1633    PHP_FE(xcache_get,               NULL)
1634    PHP_FE(xcache_set,               NULL)
1635    PHP_FE(xcache_isset,             NULL)
1636    PHP_FE(xcache_unset,             NULL)
1637    {NULL, NULL,                     NULL}
1638};
1639/* }}} */
1640
1641/* signal handler */
1642static void (*original_sigsegv_handler)(int) = NULL;
1643static void xcache_sigsegv_handler(int dummy) /* {{{ */
1644{
1645    if (original_sigsegv_handler == xcache_sigsegv_handler) {
1646        signal(SIGSEGV, original_sigsegv_handler);
1647    }
1648    else {
1649        signal(SIGSEGV, SIG_DFL);
1650    }
1651    if (xc_coredump_dir && xc_coredump_dir[0]) {
1652        chdir(xc_coredump_dir);
1653    }
1654    if (original_sigsegv_handler != xcache_sigsegv_handler) {
1655        original_sigsegv_handler(dummy);
1656    }
1657}
1658/* }}} */
1659
1660/* {{{ PHP_INI */
1661static PHP_INI_MH(xc_OnUpdateLong)
1662{
1663    long *p = (long *)mh_arg1;
1664    *p = zend_atoi(new_value, new_value_length);
1665    return SUCCESS;
1666}
1667
1668static PHP_INI_MH(xc_OnUpdateBool)
1669{
1670    zend_bool *p = (zend_bool *)mh_arg1;
1671
1672    if (strncasecmp("on", new_value, sizeof("on"))) {
1673        *p = (zend_bool) atoi(new_value);
1674    }
1675    else {
1676        *p = (zend_bool) 1;
1677    }
1678    return SUCCESS;
1679}
1680
1681static PHP_INI_MH(xc_OnUpdateHashInfo)
1682{
1683    xc_hash_t *p = (xc_hash_t *)mh_arg1;
1684    int bits, size;
1685
1686    p->size = zend_atoi(new_value, new_value_length);
1687    for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
1688        /* empty body */
1689    }
1690    p->size = size;
1691    p->bits = bits;
1692    p->mask = size - 1;
1693
1694    return SUCCESS;
1695}
1696
1697static PHP_INI_MH(xc_OnUpdateString)
1698{
1699    char **p = (char**)mh_arg1;
1700    if (*p) {
1701        pefree(*p, 1);
1702    }
1703    *p = pemalloc(strlen(new_value) + 1, 1);
1704    strcpy(*p, new_value);
1705    return SUCCESS;
1706}
1707#ifdef ZEND_ENGINE_2
1708#define OnUpdateInt OnUpdateLong
1709#endif
1710
1711PHP_INI_BEGIN()
1712    PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateLong,     &xc_php_size)
1713    PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_php_hcache)
1714    PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_php_hentry)
1715
1716    PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateLong,     &xc_var_size)
1717    PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_var_hcache)
1718    PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_var_hentry)
1719
1720    PHP_INI_ENTRY1     ("xcache.mmap_path",      "/dev/zero", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
1721    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
1722    PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
1723    PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
1724
1725    STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
1726#ifdef HAVE_XCACHE_OPTIMIZER
1727    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
1728#endif
1729#ifdef HAVE_XCACHE_COVERAGE
1730    PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coveragedump_dir)
1731    STD_PHP_INI_BOOLEAN("xcache.coveragedumper" ,        "1", PHP_INI_ALL,    OnUpdateBool,        coveragedumper,    zend_xcache_globals, xcache_globals)
1732#endif
1733PHP_INI_END()
1734/* }}} */
1735/* {{{ PHP_MINFO_FUNCTION(xcache) */
1736static PHP_MINFO_FUNCTION(xcache)
1737{
1738    php_info_print_table_start();
1739    php_info_print_table_header(2, "XCache Support", (xc_php_size || xc_var_size) ? "enabled" : "disabled");
1740    php_info_print_table_row(2, "Version", XCACHE_VERSION);
1741    php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
1742    php_info_print_table_row(2, "Opcode Cache", xc_php_size ? "enabled" : "disabled");
1743    php_info_print_table_row(2, "Variable Cache", xc_var_size ? "enabled" : "disabled");
1744    php_info_print_table_end();
1745    DISPLAY_INI_ENTRIES();
1746}
1747/* }}} */
1748/* {{{ extension startup */
1749static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
1750{
1751    zend_extension extension;
1752
1753    extension = *new_extension;
1754    extension.handle = handle;
1755
1756    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
1757
1758    zend_llist_add_element(&zend_extensions, &extension);
1759#ifdef DEBUG
1760    fprintf(stderr, "registered\n");
1761#endif
1762}
1763
1764/* dirty check */
1765#if defined(COMPILE_DL_XCACHE) && (defined(ZEND_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__))
1766#   define zend_append_version_info(x) do { } while (0)
1767#else
1768extern void zend_append_version_info(zend_extension *extension);
1769#endif
1770static int xc_zend_extension_startup(zend_extension *extension)
1771{
1772    if (extension->startup) {
1773        if (extension->startup(extension) != SUCCESS) {
1774            return FAILURE;
1775        }
1776        zend_append_version_info(extension);
1777    }
1778    return SUCCESS;
1779}
1780/* }}} */
1781/* {{{ PHP_MINIT_FUNCTION(xcache) */
1782static PHP_MINIT_FUNCTION(xcache)
1783{
1784    char *env;
1785
1786    xc_module_gotup = 1;
1787    if (!xc_zend_extension_gotup) {
1788        if (zend_get_extension(XCACHE_NAME) == NULL) {
1789            xc_zend_extension_register(&zend_extension_entry, 0);
1790            xc_zend_extension_startup(&zend_extension_entry);
1791        }
1792    }
1793
1794    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
1795    REGISTER_INI_ENTRIES();
1796
1797    if (strcmp(sapi_module.name, "cli") == 0) {
1798        if ((env = getenv("XCACHE_TEST")) != NULL) {
1799            zend_alter_ini_entry("xcache.test", sizeof("xcache.test"), env, strlen(env) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP);
1800        }
1801        if (!xc_test) {
1802            /* disable cache for cli except for test */
1803            xc_php_size = xc_var_size = 0;
1804        }
1805    }
1806
1807    if (xc_php_size <= 0) {
1808        xc_php_size = xc_php_hcache.size = 0;
1809    }
1810    if (xc_var_size <= 0) {
1811        xc_var_size = xc_var_hcache.size = 0;
1812    }
1813
1814    original_sigsegv_handler = signal(SIGSEGV, xcache_sigsegv_handler);
1815
1816    xc_init_constant(module_number TSRMLS_CC);
1817
1818    if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
1819        if (!xc_init(module_number TSRMLS_CC)) {
1820            zend_error(E_ERROR, "XCache: Cannot init xcache");
1821            goto err_init;
1822        }
1823        xc_initized = 1;
1824    }
1825
1826#ifdef HAVE_XCACHE_COVERAGE
1827    xc_coverage_init(module_number TSRMLS_CC);
1828#endif
1829
1830    return SUCCESS;
1831
1832err_init:
1833    return FAILURE;
1834}
1835/* }}} */
1836/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
1837static PHP_MSHUTDOWN_FUNCTION(xcache)
1838{
1839    if (xc_initized) {
1840        xc_destroy();
1841        xc_initized = 0;
1842    }
1843    if (xc_mmap_path) {
1844        pefree(xc_mmap_path, 1);
1845        xc_mmap_path = NULL;
1846    }
1847
1848#ifdef HAVE_XCACHE_COVERAGE
1849    xc_coverage_destroy();
1850#endif
1851
1852    signal(SIGSEGV, original_sigsegv_handler);
1853    if (xc_coredump_dir) {
1854        pefree(xc_coredump_dir, 1);
1855        xc_coredump_dir = NULL;
1856    }
1857#ifndef ZTS
1858    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
1859#endif
1860
1861    UNREGISTER_INI_ENTRIES();
1862    return SUCCESS;
1863}
1864/* }}} */
1865/* {{{ PHP_RINIT_FUNCTION(xcache) */
1866static PHP_RINIT_FUNCTION(xcache)
1867{
1868    xc_request_init(TSRMLS_C);
1869    return SUCCESS;
1870}
1871/* }}} */
1872/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
1873#ifndef ZEND_ENGINE_2
1874static PHP_RSHUTDOWN_FUNCTION(xcache)
1875#else
1876static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
1877#endif
1878{
1879    TSRMLS_FETCH();
1880
1881    xc_request_shutdown(TSRMLS_C);
1882    return SUCCESS;
1883}
1884/* }}} */
1885/* {{{ module definition structure */
1886
1887zend_module_entry xcache_module_entry = {
1888    STANDARD_MODULE_HEADER,
1889    "xcache",
1890    xcache_functions,
1891    PHP_MINIT(xcache),
1892    PHP_MSHUTDOWN(xcache),
1893    PHP_RINIT(xcache),
1894#ifndef ZEND_ENGINE_2
1895    PHP_RSHUTDOWN(xcache),
1896#else
1897    NULL,
1898#endif
1899    PHP_MINFO(xcache),
1900    XCACHE_VERSION,
1901#ifdef ZEND_ENGINE_2
1902    ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
1903#else
1904    NULL,
1905    NULL,
1906#endif
1907    STANDARD_MODULE_PROPERTIES_EX
1908};
1909
1910#ifdef COMPILE_DL_XCACHE
1911ZEND_GET_MODULE(xcache)
1912#endif
1913/* }}} */
1914ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
1915{
1916    if (xc_zend_extension_gotup) {
1917        return FAILURE;
1918    }
1919    xc_zend_extension_gotup = 1;
1920    if (!xc_module_gotup) {
1921        return zend_startup_module(&xcache_module_entry);
1922    }
1923    return SUCCESS;
1924}
1925/* }}} */
1926ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
1927{
1928    /* empty */
1929}
1930/* }}} */
1931ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
1932{
1933#ifdef HAVE_XCACHE_COVERAGE
1934    xc_coverage_handle_ext_stmt(op_array, ZEND_EXT_STMT);
1935#endif
1936}
1937/* }}} */
1938ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
1939{
1940#if 0
1941    xc_coverage_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
1942#endif
1943}
1944/* }}} */
1945ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
1946{
1947#if 0
1948    xc_coverage_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
1949#endif
1950}
1951/* }}} */
1952/* {{{ zend extension definition structure */
1953ZEND_DLEXPORT zend_extension zend_extension_entry = {
1954    XCACHE_NAME,
1955    XCACHE_VERSION,
1956    XCACHE_AUTHOR,
1957    XCACHE_URL,
1958    XCACHE_COPYRIGHT,
1959    xcache_zend_startup,
1960    xcache_zend_shutdown,
1961    NULL,           /* activate_func_t */
1962    NULL,           /* deactivate_func_t */
1963    NULL,           /* message_handler_func_t */
1964    NULL,           /* op_array_handler_func_t */
1965    xcache_statement_handler,
1966    xcache_fcall_begin_handler,
1967    xcache_fcall_end_handler,
1968    NULL,           /* op_array_ctor_func_t */
1969    NULL,           /* op_array_dtor_func_t */
1970    STANDARD_ZEND_EXTENSION_PROPERTIES
1971};
1972
1973#ifndef ZEND_EXT_API
1974#   define ZEND_EXT_API ZEND_DLEXPORT
1975#endif
1976#if COMPILE_DL_XCACHE
1977ZEND_EXTENSION();
1978#endif
1979/* }}} */
Note: See TracBrowser for help on using the repository browser.