source: trunk/xcache.c @ 18

Last change on this file since 18 was 18, checked in by moo, 9 years ago

fix win32/vc build for php4

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