source: trunk/xcache.c @ 11

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

make it build on windows vc compiler

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