source: trunk/xcache.c @ 9

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

update proto description

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