source: trunk/xcache.c @ 27

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

rename coverage -> coverager

File size: 48.8 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 "coverager.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(NOTHING, 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(NOTHING, 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(NOTHING, 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(NOTHING, 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        zend_uchar (*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    zend_uchar i, count;
844    char const_name[96];
845    int const_name_len;
846    int undefdone = 0;
847
848    for (p = nameinfos; p->getsize; p ++) {
849        count = p->getsize();
850        for (i = 0; i < count; i ++) {
851            const char *name = p->get(i);
852            if (!name) continue;
853            if (strcmp(name, "UNDEF") == 0) {
854                if (undefdone) continue;
855                undefdone = 1;
856            }
857            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
858            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
859        }
860    }
861
862    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
863    zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
864    zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
865    return 0;
866}
867/* }}} */
868static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
869{
870    int i;
871    xc_cache_t *cache;
872    xc_shm_t *shm;
873
874    if (!caches) {
875        return NULL;
876    }
877    shm = NULL;
878    for (i = 0; i < hcache->size; i ++) {
879        cache = caches[i];
880        if (cache) {
881            if (cache->lck) {
882                xc_lock_destroy(cache->lck);
883            }
884            /* do NOT free
885            if (cache->entries) {
886                xc_mem_free(cache->mem, cache->entries);
887            }
888            xc_mem_free(cache->mem, cache);
889            */
890            xc_mem_destroy(cache->mem);
891            shm = cache->shm;
892        }
893    }
894    free(caches);
895    return shm;
896}
897/* }}} */
898static xc_cache_t **xc_cache_init(xc_shm_t *shm, char *ptr, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */
899{
900    xc_cache_t **caches = NULL, *cache;
901    xc_mem_t *mem;
902    int i;
903
904    xc_memsize_t memsize = shmsize / hcache->size;
905
906    CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
907
908    for (i = 0; i < hcache->size; i ++) {
909        mem = xc_mem_init(ptr, memsize);
910        ptr += ALIGN(memsize);
911        CHECK(cache          = xc_mem_calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
912        CHECK(cache->entries = xc_mem_calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
913        CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
914
915        cache->hcache  = hcache;
916        cache->hentry  = hentry;
917        cache->shm     = shm;
918        cache->mem     = mem;
919        cache->cacheid = i;
920        caches[i] = cache;
921    }
922    assert(ptr <= (char*)xc_shm_ptr(shm) + shmsize);
923    return caches;
924
925err:
926    if (caches) {
927        xc_cache_destroy(caches, hcache);
928    }
929    return NULL;
930}
931/* }}} */
932static void xc_destroy() /* {{{ */
933{
934    xc_shm_t *shm = NULL;
935
936    if (origin_compile_file) {
937        zend_compile_file = origin_compile_file;
938        origin_compile_file = NULL;
939    }
940
941    if (xc_php_caches) {
942        shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
943        xc_php_caches = NULL;
944    }
945    if (xc_var_caches) {
946        shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
947        xc_var_caches = NULL;
948    }
949    if (shm) {
950        xc_shm_destroy(shm);
951    }
952}
953/* }}} */
954static int xc_init(int module_number TSRMLS_DC) /* {{{ */
955{
956    xc_shm_t *shm;
957    char *ptr;
958
959    xc_php_caches = xc_var_caches = NULL;
960
961    if (xc_php_size || xc_var_size) {
962        CHECK(shm = xc_shm_init(xc_mmap_path, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection), "Cannot create shm");
963        if (!xc_shm_can_readonly(shm)) {
964            xc_readonly_protection = 0;
965        }
966
967        ptr = (char *)xc_shm_ptr(shm);
968        if (xc_php_size) {
969            origin_compile_file = zend_compile_file;
970            zend_compile_file = xc_compile_file;
971
972            CHECK(xc_php_caches = xc_cache_init(shm, ptr, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
973            ptr += ALIGN(xc_php_size);
974        }
975
976        if (xc_var_size) {
977            CHECK(xc_var_caches = xc_cache_init(shm, ptr, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache");
978        }
979    }
980    return 1;
981
982err:
983    if (xc_php_caches || xc_var_caches) {
984        xc_destroy();
985        /* shm destroied */
986    }
987    else if (shm) {
988        xc_shm_destroy(shm);
989    }
990    return 0;
991}
992/* }}} */
993static void xc_request_init(TSRMLS_D) /* {{{ */
994{
995    int i;
996
997    if (xc_php_hcache.size && !XG(php_holds)) {
998        XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
999        for (i = 0; i < xc_php_hcache.size; i ++) {
1000            xc_stack_init(&XG(php_holds[i]));
1001        }
1002    }
1003
1004    if (xc_var_hcache.size && !XG(var_holds)) {
1005        XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
1006        for (i = 0; i < xc_var_hcache.size; i ++) {
1007            xc_stack_init(&XG(var_holds[i]));
1008        }
1009    }
1010
1011    if (XG(cacher)) {
1012#if PHP_API_VERSION <= 20041225
1013        XG(request_time) = time(NULL);
1014#else
1015        XG(request_time) = sapi_get_request_time(TSRMLS_C);
1016#endif
1017    }
1018#ifdef HAVE_XCACHE_COVERAGER
1019    xc_coverager_request_init(TSRMLS_C);
1020#endif
1021}
1022/* }}} */
1023static void xc_request_shutdown(TSRMLS_D) /* {{{ */
1024{
1025    xc_entry_unholds(TSRMLS_C);
1026#ifdef HAVE_XCACHE_COVERAGER
1027    xc_coverager_request_shutdown(TSRMLS_C);
1028#endif
1029}
1030/* }}} */
1031static void xc_init_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
1032{
1033    memset(xc_globals, 0, sizeof(zend_xcache_globals));
1034}
1035/* }}} */
1036static void xc_shutdown_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
1037{
1038    int i;
1039
1040    if (xc_globals->php_holds != NULL) {
1041        for (i = 0; i < xc_php_hcache.size; i ++) {
1042            xc_stack_destroy(&xc_globals->php_holds[i]);
1043        }
1044        free(xc_globals->php_holds);
1045        xc_globals->php_holds = NULL;
1046    }
1047
1048    if (xc_globals->var_holds != NULL) {
1049        for (i = 0; i < xc_var_hcache.size; i ++) {
1050            xc_stack_destroy(&xc_globals->var_holds[i]);
1051        }
1052        free(xc_globals->var_holds);
1053        xc_globals->var_holds = NULL;
1054    }
1055}
1056/* }}} */
1057
1058/* user functions */
1059/* {{{ xcache_op */
1060typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
1061static void xcache_op(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
1062{
1063    long type;
1064    int size;
1065    xc_cache_t **caches, *cache;
1066    long id = 0;
1067
1068    if (!xc_initized) {
1069        php_error_docref(NULL TSRMLS_CC, E_WARNING, "XCache is not initized");
1070        RETURN_FALSE;
1071    }
1072
1073    if (optype == XC_OP_COUNT) {
1074        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
1075            return;
1076        }
1077    }
1078    else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
1079        return;
1080    }
1081
1082    switch (type) {
1083        case XC_TYPE_PHP:
1084            size = xc_php_hcache.size;
1085            caches = xc_php_caches;
1086            break;
1087
1088        case XC_TYPE_VAR:
1089            size = xc_var_hcache.size;
1090            caches = xc_var_caches;
1091            break;
1092
1093        default:
1094            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
1095            RETURN_FALSE;
1096    }
1097
1098    switch (optype) {
1099        case XC_OP_COUNT:
1100            RETURN_LONG(size)
1101            break;
1102
1103        case XC_OP_INFO:
1104        case XC_OP_LIST:
1105            if (id < 0 || id >= size) {
1106                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1107                RETURN_FALSE;
1108            }
1109
1110            array_init(return_value);
1111
1112            cache = caches[id];
1113            ENTER_LOCK(cache) {
1114                if (optype == XC_OP_INFO) {
1115                    xc_fillinfo_dmz(cache, return_value TSRMLS_CC);
1116                }
1117                else {
1118                    xc_filllist_dmz(cache, return_value TSRMLS_CC);
1119                }
1120            } LEAVE_LOCK(cache);
1121            break;
1122        case XC_OP_CLEAR:
1123            {
1124                xc_entry_t *e;
1125                int i, c;
1126
1127                if (id < 0 || id >= size) {
1128                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1129                    RETURN_FALSE;
1130                }
1131
1132                cache = caches[id];
1133                ENTER_LOCK(cache) {
1134                    for (i = 0, c = cache->hentry->size; i < c; i ++) {
1135                        for (e = cache->entries[i]; e; e = e->next) {
1136                            xc_entry_remove_dmz(e TSRMLS_CC);
1137                        }
1138                        cache->entries[i] = NULL;
1139                    }
1140                } LEAVE_LOCK(cache);
1141                xc_entry_gc(TSRMLS_C);
1142            }
1143            break;
1144
1145        default:
1146            assert(0);
1147    }
1148}
1149/* }}} */
1150/* {{{ proto int xcache_count(int type)
1151   Return count of cache on specified cache type */
1152PHP_FUNCTION(xcache_count)
1153{
1154    xcache_op(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1155}
1156/* }}} */
1157/* {{{ proto array xcache_info(int type, int id)
1158   Get cache info by id on specified cache type */
1159PHP_FUNCTION(xcache_info)
1160{
1161    xcache_op(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1162}
1163/* }}} */
1164/* {{{ proto array xcache_list(int type, int id)
1165   Get cache entries list by id on specified cache type */
1166PHP_FUNCTION(xcache_list)
1167{
1168    xcache_op(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1169}
1170/* }}} */
1171/* {{{ proto array xcache_clear_cache(int type, int id)
1172   Clear cache by id on specified cache type */
1173PHP_FUNCTION(xcache_clear_cache)
1174{
1175    xcache_op(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1176}
1177/* }}} */
1178
1179static int xc_entry_init_key_var(xc_entry_t *xce, zval *name TSRMLS_DC) /* {{{ */
1180{
1181    xc_hash_value_t hv;
1182    int cacheid;
1183
1184    switch (Z_TYPE_P(name)) {
1185#ifdef IS_UNICODE
1186        case IS_UNICODE:
1187#endif
1188        case IS_STRING:
1189            break;
1190        default:
1191#ifdef IS_UNICODE
1192            convert_to_text(name);
1193#else
1194            convert_to_string(name);
1195#endif
1196    }
1197#ifdef IS_UNICODE
1198    xce->name_type = name->type;
1199#endif
1200    xce->name = name->value;
1201
1202    hv = xc_entry_hash_var(xce);
1203
1204    cacheid = (hv & xc_var_hcache.mask);
1205    xce->cache = xc_var_caches[cacheid];
1206    hv >>= xc_var_hcache.bits;
1207    xce->hvalue = (hv & xc_var_hentry.mask);
1208
1209    xce->type = XC_TYPE_VAR;
1210    return SUCCESS;
1211}
1212/* }}} */
1213#define TIME_MAX (sizeof(time_t) == sizeof(long) ? LONG_MAX : INT_MAX)
1214/* {{{ proto mixed xcache_get(string name)
1215   Get cached data by specified name */
1216PHP_FUNCTION(xcache_get)
1217{
1218    xc_entry_t xce, *stored_xce;
1219    xc_entry_data_var_t var;
1220    zval *name;
1221
1222    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1223        return;
1224    }
1225    xce.data.var = &var;
1226    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1227
1228    ENTER_LOCK(xce.cache) {
1229        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1230        if (stored_xce) {
1231            if (XG(request_time) <= stored_xce->data.var->etime) {
1232                xc_processor_restore_zval(return_value, stored_xce->data.var->value TSRMLS_CC);
1233                /* return */
1234                break;
1235            }
1236            else {
1237                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1238            }
1239        }
1240
1241        RETVAL_NULL();
1242    } LEAVE_LOCK(xce.cache);
1243}
1244/* }}} */
1245/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
1246   Store data to cache by specified name */
1247PHP_FUNCTION(xcache_set)
1248{
1249    xc_entry_t xce, *stored_xce;
1250    xc_entry_data_var_t var;
1251    zval *name;
1252    zval *value;
1253    long ttl = 0;
1254
1255    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &ttl) == FAILURE) {
1256        return;
1257    }
1258    xce.data.var = &var;
1259    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1260
1261    ENTER_LOCK(xce.cache) {
1262        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1263        if (stored_xce) {
1264            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1265        }
1266        var.value = value;
1267        var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
1268        RETVAL_BOOL(xc_entry_store_dmz(&xce TSRMLS_CC) != NULL ? 1 : 0);
1269    } LEAVE_LOCK(xce.cache);
1270}
1271/* }}} */
1272/* {{{ proto bool  xcache_isset(string name)
1273   Check if an entry exists in cache by specified name */
1274PHP_FUNCTION(xcache_isset)
1275{
1276    xc_entry_t xce, *stored_xce;
1277    xc_entry_data_var_t var;
1278    zval *name;
1279
1280    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1281        return;
1282    }
1283    xce.data.var = &var;
1284    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1285
1286    ENTER_LOCK(xce.cache) {
1287        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1288        if (stored_xce) {
1289            if (XG(request_time) <= stored_xce->data.var->etime) {
1290                RETVAL_TRUE;
1291                /* return */
1292                break;
1293            }
1294            else {
1295                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1296            }
1297        }
1298
1299        RETVAL_FALSE;
1300    } LEAVE_LOCK(xce.cache);
1301}
1302/* }}} */
1303/* {{{ proto bool  xcache_unset(string name)
1304   Unset existing data in cache by specified name */
1305PHP_FUNCTION(xcache_unset)
1306{
1307    xc_entry_t xce, *stored_xce;
1308    xc_entry_data_var_t var;
1309    zval *name;
1310
1311    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1312        return;
1313    }
1314    xce.data.var = &var;
1315    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1316
1317    ENTER_LOCK(xce.cache) {
1318        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1319        if (stored_xce) {
1320            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1321            RETVAL_TRUE;
1322        }
1323        else {
1324            RETVAL_FALSE;
1325        }
1326    } LEAVE_LOCK(xce.cache);
1327}
1328/* }}} */
1329static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
1330{
1331    xc_entry_t xce, *stored_xce;
1332    xc_entry_data_var_t var, *stored_var;
1333    zval *name;
1334    long count = 1;
1335    long ttl = 0;
1336    long value = 0;
1337    zval oldzval;
1338
1339    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &ttl) == FAILURE) {
1340        return;
1341    }
1342    xce.data.var = &var;
1343    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1344
1345    ENTER_LOCK(xce.cache) {
1346        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1347        if (stored_xce) {
1348#ifdef DEBUG
1349            fprintf(stderr, "incdec: gotxce %s\n", xce.name.str.val);
1350#endif
1351            stored_var = stored_xce->data.var;
1352            /* timeout */
1353            if (XG(request_time) > stored_var->etime) {
1354#ifdef DEBUG
1355                fprintf(stderr, "incdec: expired\n");
1356#endif
1357                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1358                stored_xce = NULL;
1359            }
1360            else {
1361                /* do it in place */
1362                if (Z_TYPE_P(stored_var->value) == IS_LONG) {
1363#ifdef DEBUG
1364                    fprintf(stderr, "incdec: islong\n");
1365#endif
1366                    value = Z_LVAL_P(stored_var->value);
1367                    value += (inc == 1 ? count : - count);
1368                    RETVAL_LONG(value);
1369                    Z_LVAL_P(stored_var->value) = value;
1370                    break;
1371                }
1372                else {
1373#ifdef DEBUG
1374                    fprintf(stderr, "incdec: notlong\n");
1375#endif
1376                    xc_processor_restore_zval(&oldzval, stored_xce->data.var->value TSRMLS_CC);
1377                    convert_to_long(&oldzval);
1378                    value = Z_LVAL(oldzval);
1379                    zval_dtor(&oldzval);
1380                }
1381            }
1382        }
1383#ifdef DEBUG
1384        else {
1385            fprintf(stderr, "incdec: %s not found\n", xce.name.str.val);
1386        }
1387#endif
1388
1389        value += (inc == 1 ? count : - count);
1390        RETVAL_LONG(value);
1391        var.value = return_value;
1392        var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
1393        if (stored_xce) {
1394            xce.atime = stored_xce->atime;
1395            xce.ctime = stored_xce->ctime;
1396            xce.hits  = stored_xce->hits;
1397            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
1398        }
1399        xc_entry_store_dmz(&xce TSRMLS_CC);
1400
1401    } LEAVE_LOCK(xce.cache);
1402}
1403/* }}} */
1404/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
1405   Increase an int counter in cache by specified name, create it if not exists */
1406PHP_FUNCTION(xcache_inc)
1407{
1408    xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1409}
1410/* }}} */
1411/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
1412   Decrease an int counter in cache by specified name, create it if not exists */
1413PHP_FUNCTION(xcache_dec)
1414{
1415    xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1416}
1417/* }}} */
1418/* {{{ proto string xcache_asm(string filename)
1419 */
1420#ifdef HAVE_XCACHE_ASSEMBLER
1421PHP_FUNCTION(xcache_asm)
1422{
1423}
1424#endif
1425/* }}} */
1426#ifdef HAVE_XCACHE_DISASSEMBLER
1427/* {{{ proto array  xcache_dasm_file(string filename)
1428   Disassemble file into opcode array by filename */
1429PHP_FUNCTION(xcache_dasm_file)
1430{
1431    char *filename;
1432    long filename_len;
1433
1434    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1435        return;
1436    }
1437    if (!filename_len) RETURN_FALSE;
1438
1439    xc_dasm_file(return_value, filename TSRMLS_CC);
1440}
1441/* }}} */
1442/* {{{ proto array  xcache_dasm_string(string code)
1443   Disassemble php code into opcode array */
1444PHP_FUNCTION(xcache_dasm_string)
1445{
1446    zval *code;
1447
1448    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
1449        return;
1450    }
1451    xc_dasm_string(return_value, code TSRMLS_CC);
1452}
1453/* }}} */
1454#endif
1455/* {{{ proto string xcache_encode(string filename)
1456   Encode php file into XCache opcode encoded format */
1457#ifdef HAVE_XCACHE_ENCODER
1458PHP_FUNCTION(xcache_encode)
1459{
1460}
1461#endif
1462/* }}} */
1463/* {{{ proto bool xcache_decode_file(string filename)
1464   Decode(load) opcode from XCache encoded format file */
1465#ifdef HAVE_XCACHE_DECODER
1466PHP_FUNCTION(xcache_decode_file)
1467{
1468}
1469#endif
1470/* }}} */
1471/* {{{ proto bool xcache_decode_string(string data)
1472   Decode(load) opcode from XCache encoded format data */
1473#ifdef HAVE_XCACHE_DECODER
1474PHP_FUNCTION(xcache_decode_string)
1475{
1476}
1477#endif
1478/* }}} */
1479/* {{{ xc_call_getter */
1480typedef const char *(xc_name_getter_t)(zend_uchar type);
1481static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
1482{
1483    long spec;
1484    const char *name;
1485
1486    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1487        return;
1488    }
1489    if (spec >= 0 && spec < count) {
1490        name = getter((zend_uchar) spec);
1491        if (name) {
1492            /* RETURN_STRING */
1493            int len = strlen(name);
1494            return_value->value.str.len = len;
1495            return_value->value.str.val = estrndup(name, len);
1496            return_value->type = IS_STRING; 
1497            return;
1498        }
1499    }
1500    RETURN_NULL();
1501}
1502/* }}} */
1503/* {{{ proto string xcache_get_op_type(int op_type) */
1504PHP_FUNCTION(xcache_get_op_type)
1505{
1506    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1507}
1508/* }}} */
1509/* {{{ proto string xcache_get_data_type(int type) */
1510PHP_FUNCTION(xcache_get_data_type)
1511{
1512    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1513}
1514/* }}} */
1515/* {{{ proto string xcache_get_opcode(int opcode) */
1516PHP_FUNCTION(xcache_get_opcode)
1517{
1518    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1519}
1520/* }}} */
1521/* {{{ proto string xcache_get_op_spec(int op_type) */
1522PHP_FUNCTION(xcache_get_op_spec)
1523{
1524    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1525}
1526/* }}} */
1527#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
1528/* {{{ proto string xcache_get_opcode_spec(int opcode) */
1529PHP_FUNCTION(xcache_get_opcode_spec)
1530{
1531    long spec;
1532    const xc_opcode_spec_t *opspec;
1533
1534    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1535        return;
1536    }
1537    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
1538        opspec = xc_get_opcode_spec((zend_uchar) spec);
1539        if (opspec) {
1540            array_init(return_value);
1541            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
1542            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
1543            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
1544            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
1545            return;
1546        }
1547    }
1548    RETURN_NULL();
1549}
1550/* }}} */
1551#endif
1552/* {{{ proto mixed xcache_get_special_value(zval value) */
1553PHP_FUNCTION(xcache_get_special_value)
1554{
1555    zval *value;
1556
1557    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
1558        return;
1559    }
1560
1561    if (value->type == IS_CONSTANT) {
1562        *return_value = *value;
1563        zval_copy_ctor(return_value);
1564        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
1565        return;
1566    }
1567
1568    if (value->type == IS_CONSTANT_ARRAY) {
1569        *return_value = *value;
1570        zval_copy_ctor(return_value);
1571        return_value->type = IS_ARRAY;
1572        return;
1573    }
1574
1575    RETURN_NULL();
1576}
1577/* }}} */
1578/* {{{ proto string xcache_coredump(int op_type) */
1579PHP_FUNCTION(xcache_coredump)
1580{
1581    if (xc_test) {
1582        raise(SIGSEGV);
1583    }
1584    else {
1585        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
1586    }
1587}
1588/* }}} */
1589/* {{{ proto string xcache_is_autoglobal(string name) */
1590PHP_FUNCTION(xcache_is_autoglobal)
1591{
1592    char *name;
1593    long name_len;
1594
1595    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
1596        return;
1597    }
1598
1599    RETURN_BOOL(zend_hash_exists(CG(auto_globals), name, name_len + 1));
1600}
1601/* }}} */
1602static function_entry xcache_functions[] = /* {{{ */
1603{
1604    PHP_FE(xcache_count,             NULL)
1605    PHP_FE(xcache_info,              NULL)
1606    PHP_FE(xcache_list,              NULL)
1607    PHP_FE(xcache_clear_cache,       NULL)
1608    PHP_FE(xcache_coredump,          NULL)
1609#ifdef HAVE_XCACHE_ASSEMBLER
1610    PHP_FE(xcache_asm,               NULL)
1611#endif
1612#ifdef HAVE_XCACHE_DISASSEMBLER
1613    PHP_FE(xcache_dasm_file,         NULL)
1614    PHP_FE(xcache_dasm_string,       NULL)
1615#endif
1616#ifdef HAVE_XCACHE_ENCODER
1617    PHP_FE(xcache_encode,            NULL)
1618#endif
1619#ifdef HAVE_XCACHE_DECODER
1620    PHP_FE(xcache_decode_file,       NULL)
1621    PHP_FE(xcache_decode_string,     NULL)
1622#endif
1623#ifdef HAVE_XCACHE_COVERAGER
1624    PHP_FE(xcache_coverager_decode,  NULL)
1625#endif
1626    PHP_FE(xcache_get_special_value, NULL)
1627    PHP_FE(xcache_get_op_type,       NULL)
1628    PHP_FE(xcache_get_data_type,     NULL)
1629    PHP_FE(xcache_get_opcode,        NULL)
1630#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
1631    PHP_FE(xcache_get_opcode_spec,   NULL)
1632#endif
1633    PHP_FE(xcache_is_autoglobal,     NULL)
1634    PHP_FE(xcache_inc,               NULL)
1635    PHP_FE(xcache_dec,               NULL)
1636    PHP_FE(xcache_get,               NULL)
1637    PHP_FE(xcache_set,               NULL)
1638    PHP_FE(xcache_isset,             NULL)
1639    PHP_FE(xcache_unset,             NULL)
1640    {NULL, NULL,                     NULL}
1641};
1642/* }}} */
1643
1644/* signal handler */
1645static void (*original_sigsegv_handler)(int) = NULL;
1646static void xcache_sigsegv_handler(int dummy) /* {{{ */
1647{
1648    if (original_sigsegv_handler == xcache_sigsegv_handler) {
1649        signal(SIGSEGV, original_sigsegv_handler);
1650    }
1651    else {
1652        signal(SIGSEGV, SIG_DFL);
1653    }
1654    if (xc_coredump_dir && xc_coredump_dir[0]) {
1655        chdir(xc_coredump_dir);
1656    }
1657    if (original_sigsegv_handler != xcache_sigsegv_handler) {
1658        original_sigsegv_handler(dummy);
1659    }
1660}
1661/* }}} */
1662
1663/* {{{ PHP_INI */
1664static PHP_INI_MH(xc_OnUpdateLong)
1665{
1666    long *p = (long *)mh_arg1;
1667    *p = zend_atoi(new_value, new_value_length);
1668    return SUCCESS;
1669}
1670
1671static PHP_INI_MH(xc_OnUpdateBool)
1672{
1673    zend_bool *p = (zend_bool *)mh_arg1;
1674
1675    if (strncasecmp("on", new_value, sizeof("on"))) {
1676        *p = (zend_bool) atoi(new_value);
1677    }
1678    else {
1679        *p = (zend_bool) 1;
1680    }
1681    return SUCCESS;
1682}
1683
1684static PHP_INI_MH(xc_OnUpdateHashInfo)
1685{
1686    xc_hash_t *p = (xc_hash_t *)mh_arg1;
1687    int bits, size;
1688
1689    p->size = zend_atoi(new_value, new_value_length);
1690    for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
1691        /* empty body */
1692    }
1693    p->size = size;
1694    p->bits = bits;
1695    p->mask = size - 1;
1696
1697    return SUCCESS;
1698}
1699
1700static PHP_INI_MH(xc_OnUpdateString)
1701{
1702    char **p = (char**)mh_arg1;
1703    if (*p) {
1704        pefree(*p, 1);
1705    }
1706    *p = pemalloc(strlen(new_value) + 1, 1);
1707    strcpy(*p, new_value);
1708    return SUCCESS;
1709}
1710#ifdef ZEND_ENGINE_2
1711#define OnUpdateInt OnUpdateLong
1712#endif
1713
1714#ifdef ZEND_WIN32
1715#   define DEFAULT_PATH "xcache"
1716#else
1717#   define DEFAULT_PATH "/dev/zero"
1718#endif
1719PHP_INI_BEGIN()
1720    PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateLong,     &xc_php_size)
1721    PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_php_hcache)
1722    PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_php_hentry)
1723
1724    PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateLong,     &xc_var_size)
1725    PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_var_hcache)
1726    PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateHashInfo, &xc_var_hentry)
1727
1728    PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
1729    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
1730    PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
1731    PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
1732
1733    STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
1734#ifdef HAVE_XCACHE_OPTIMIZER
1735    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
1736#endif
1737#ifdef HAVE_XCACHE_COVERAGER
1738    PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coveragedump_dir)
1739    STD_PHP_INI_BOOLEAN("xcache.coveragedumper" ,        "1", PHP_INI_ALL,    OnUpdateBool,        coveragedumper,    zend_xcache_globals, xcache_globals)
1740#endif
1741PHP_INI_END()
1742/* }}} */
1743/* {{{ PHP_MINFO_FUNCTION(xcache) */
1744static PHP_MINFO_FUNCTION(xcache)
1745{
1746    php_info_print_table_start();
1747    php_info_print_table_header(2, "XCache Support", (xc_php_size || xc_var_size) ? "enabled" : "disabled");
1748    php_info_print_table_row(2, "Version", XCACHE_VERSION);
1749    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
1750    php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
1751    php_info_print_table_row(2, "Opcode Cache", xc_php_size ? "enabled" : "disabled");
1752    php_info_print_table_row(2, "Variable Cache", xc_var_size ? "enabled" : "disabled");
1753#ifdef HAVE_XCACHE_COVERAGER
1754    php_info_print_table_row(2, "Coverage Dumper", XG(coveragedumper) && xc_coveragedump_dir && xc_coveragedump_dir[0] ? "enabled" : "disabled");
1755#endif
1756    php_info_print_table_end();
1757    DISPLAY_INI_ENTRIES();
1758}
1759/* }}} */
1760/* {{{ extension startup */
1761static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
1762{
1763    zend_extension extension;
1764
1765    extension = *new_extension;
1766    extension.handle = handle;
1767
1768    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
1769
1770    zend_llist_add_element(&zend_extensions, &extension);
1771#ifdef DEBUG
1772    fprintf(stderr, "registered\n");
1773#endif
1774}
1775
1776/* dirty check */
1777#if defined(COMPILE_DL_XCACHE) && (defined(ZEND_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__))
1778#   define zend_append_version_info(x) do { } while (0)
1779#else
1780extern void zend_append_version_info(zend_extension *extension);
1781#endif
1782static int xc_zend_extension_startup(zend_extension *extension)
1783{
1784    if (extension->startup) {
1785        if (extension->startup(extension) != SUCCESS) {
1786            return FAILURE;
1787        }
1788        zend_append_version_info(extension);
1789    }
1790    return SUCCESS;
1791}
1792/* }}} */
1793/* {{{ PHP_MINIT_FUNCTION(xcache) */
1794static PHP_MINIT_FUNCTION(xcache)
1795{
1796    char *env;
1797
1798    xc_module_gotup = 1;
1799    if (!xc_zend_extension_gotup) {
1800        if (zend_get_extension(XCACHE_NAME) == NULL) {
1801            xc_zend_extension_register(&zend_extension_entry, 0);
1802            xc_zend_extension_startup(&zend_extension_entry);
1803        }
1804    }
1805
1806    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
1807    REGISTER_INI_ENTRIES();
1808
1809    if (strcmp(sapi_module.name, "cli") == 0) {
1810        if ((env = getenv("XCACHE_TEST")) != NULL) {
1811            zend_alter_ini_entry("xcache.test", sizeof("xcache.test"), env, strlen(env) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP);
1812        }
1813        if (!xc_test) {
1814            /* disable cache for cli except for test */
1815            xc_php_size = xc_var_size = 0;
1816        }
1817    }
1818
1819    if (xc_php_size <= 0) {
1820        xc_php_size = xc_php_hcache.size = 0;
1821    }
1822    if (xc_var_size <= 0) {
1823        xc_var_size = xc_var_hcache.size = 0;
1824    }
1825
1826    original_sigsegv_handler = signal(SIGSEGV, xcache_sigsegv_handler);
1827
1828    xc_init_constant(module_number TSRMLS_CC);
1829
1830    if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
1831        if (!xc_init(module_number TSRMLS_CC)) {
1832            zend_error(E_ERROR, "XCache: Cannot init");
1833            goto err_init;
1834        }
1835        xc_initized = 1;
1836    }
1837
1838#ifdef HAVE_XCACHE_COVERAGER
1839    xc_coverager_init(module_number TSRMLS_CC);
1840#endif
1841
1842    return SUCCESS;
1843
1844err_init:
1845    return FAILURE;
1846}
1847/* }}} */
1848/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
1849static PHP_MSHUTDOWN_FUNCTION(xcache)
1850{
1851    if (xc_initized) {
1852        xc_destroy();
1853        xc_initized = 0;
1854    }
1855    if (xc_mmap_path) {
1856        pefree(xc_mmap_path, 1);
1857        xc_mmap_path = NULL;
1858    }
1859
1860#ifdef HAVE_XCACHE_COVERAGER
1861    xc_coverager_destroy();
1862#endif
1863
1864    signal(SIGSEGV, original_sigsegv_handler);
1865    if (xc_coredump_dir) {
1866        pefree(xc_coredump_dir, 1);
1867        xc_coredump_dir = NULL;
1868    }
1869#ifdef ZTS
1870    ts_free_id(xcache_globals_id);
1871#else
1872    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
1873#endif
1874
1875    UNREGISTER_INI_ENTRIES();
1876    return SUCCESS;
1877}
1878/* }}} */
1879/* {{{ PHP_RINIT_FUNCTION(xcache) */
1880static PHP_RINIT_FUNCTION(xcache)
1881{
1882    xc_request_init(TSRMLS_C);
1883    return SUCCESS;
1884}
1885/* }}} */
1886/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
1887#ifndef ZEND_ENGINE_2
1888static PHP_RSHUTDOWN_FUNCTION(xcache)
1889#else
1890static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
1891#endif
1892{
1893#ifdef ZEND_ENGINE_2
1894    TSRMLS_FETCH();
1895#endif
1896
1897    xc_request_shutdown(TSRMLS_C);
1898    return SUCCESS;
1899}
1900/* }}} */
1901/* {{{ module definition structure */
1902
1903zend_module_entry xcache_module_entry = {
1904    STANDARD_MODULE_HEADER,
1905    "XCache",
1906    xcache_functions,
1907    PHP_MINIT(xcache),
1908    PHP_MSHUTDOWN(xcache),
1909    PHP_RINIT(xcache),
1910#ifndef ZEND_ENGINE_2
1911    PHP_RSHUTDOWN(xcache),
1912#else
1913    NULL,
1914#endif
1915    PHP_MINFO(xcache),
1916    XCACHE_VERSION,
1917#ifdef ZEND_ENGINE_2
1918    ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
1919#else
1920    NULL,
1921    NULL,
1922#endif
1923    STANDARD_MODULE_PROPERTIES_EX
1924};
1925
1926#ifdef COMPILE_DL_XCACHE
1927ZEND_GET_MODULE(xcache)
1928#endif
1929/* }}} */
1930ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
1931{
1932    if (xc_zend_extension_gotup) {
1933        return FAILURE;
1934    }
1935    xc_zend_extension_gotup = 1;
1936    if (!xc_module_gotup) {
1937        return zend_startup_module(&xcache_module_entry);
1938    }
1939    return SUCCESS;
1940}
1941/* }}} */
1942ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
1943{
1944    /* empty */
1945}
1946/* }}} */
1947ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
1948{
1949#ifdef HAVE_XCACHE_COVERAGER
1950    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
1951#endif
1952}
1953/* }}} */
1954ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
1955{
1956#if 0
1957    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
1958#endif
1959}
1960/* }}} */
1961ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
1962{
1963#if 0
1964    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
1965#endif
1966}
1967/* }}} */
1968/* {{{ zend extension definition structure */
1969ZEND_DLEXPORT zend_extension zend_extension_entry = {
1970    XCACHE_NAME,
1971    XCACHE_VERSION,
1972    XCACHE_AUTHOR,
1973    XCACHE_URL,
1974    XCACHE_COPYRIGHT,
1975    xcache_zend_startup,
1976    xcache_zend_shutdown,
1977    NULL,           /* activate_func_t */
1978    NULL,           /* deactivate_func_t */
1979    NULL,           /* message_handler_func_t */
1980    NULL,           /* op_array_handler_func_t */
1981    xcache_statement_handler,
1982    xcache_fcall_begin_handler,
1983    xcache_fcall_end_handler,
1984    NULL,           /* op_array_ctor_func_t */
1985    NULL,           /* op_array_dtor_func_t */
1986    STANDARD_ZEND_EXTENSION_PROPERTIES
1987};
1988
1989#ifndef ZEND_EXT_API
1990#   define ZEND_EXT_API ZEND_DLEXPORT
1991#endif
1992#if COMPILE_DL_XCACHE
1993ZEND_EXTENSION();
1994#endif
1995/* }}} */
Note: See TracBrowser for help on using the repository browser.