source: trunk/xcache.c @ 189

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

call op_array_ctor handler on restore to be more compatible with other zend_extension

File size: 63.4 KB
RevLine 
[1]1
2#undef DEBUG
3
4/* {{{ macros */
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8
9#include <signal.h>
10
11#include "php.h"
12#include "ext/standard/info.h"
[34]13#include "ext/standard/md5.h"
[82]14#include "ext/standard/php_math.h"
[1]15#include "zend_extensions.h"
16#include "SAPI.h"
17
18#include "xcache.h"
19#include "optimizer.h"
[27]20#include "coverager.h"
[1]21#include "disassembler.h"
22#include "align.h"
23#include "stack.h"
24#include "xcache_globals.h"
25#include "processor.h"
26#include "utils.h"
27#include "const_string.h"
28#include "opcode_spec.h"
29
30#ifdef DEBUG
[18]31#   undef NDEBUG
[1]32#   undef inline
33#   define inline
34#else
[18]35#   ifndef NDEBUG
36#       define NDEBUG
37#   endif
[1]38#endif
39#include <assert.h>
40
[114]41#define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > pentry->ctime + (pentry)->ttl)
[1]42#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
43#define LOCK(x) xc_lock(x->lck)
44#define UNLOCK(x) xc_unlock(x->lck)
[130]45
46#define ENTER_LOCK_EX(x) \
[1]47    xc_lock(x->lck); \
48    zend_try { \
49        do
[130]50#define LEAVE_LOCK_EX(x) \
[1]51        while (0); \
52    } zend_catch { \
53        catched = 1; \
54    } zend_end_try(); \
[130]55    xc_unlock(x->lck)
56
57#define ENTER_LOCK(x) do { \
58    int catched = 0; \
59    ENTER_LOCK_EX(x)
60#define LEAVE_LOCK(x) \
61    LEAVE_LOCK_EX(x); \
62    if (catched) { \
63        zend_bailout(); \
64    } \
[1]65} while(0)
[130]66
[1]67/* }}} */
68
69/* {{{ globals */
[148]70static char *xc_shm_scheme = NULL;
[1]71static char *xc_mmap_path = NULL;
72static char *xc_coredump_dir = NULL;
73
74static xc_hash_t xc_php_hcache = {0};
75static xc_hash_t xc_php_hentry = {0};
76static xc_hash_t xc_var_hcache = {0};
77static xc_hash_t xc_var_hentry = {0};
78
[114]79static zend_ulong xc_php_ttl    = 0;
80static zend_ulong xc_var_maxttl = 0;
81
82enum { xc_deletes_gc_interval = 120 };
83static zend_ulong xc_php_gc_interval = 0;
84static zend_ulong xc_var_gc_interval = 0;
85
[1]86/* total size */
87static zend_ulong xc_php_size  = 0;
88static zend_ulong xc_var_size  = 0;
89
90static xc_cache_t **xc_php_caches = NULL;
91static xc_cache_t **xc_var_caches = NULL;
92
93static zend_bool xc_initized = 0;
94static zend_compile_file_t *origin_compile_file;
95
96static zend_bool xc_test = 0;
97static zend_bool xc_readonly_protection = 0;
98
[189]99zend_bool xc_have_op_array_ctor = 0;
100
[1]101static zend_bool xc_module_gotup = 0;
102static zend_bool xc_zend_extension_gotup = 0;
103#if !COMPILE_DL_XCACHE
104#   define zend_extension_entry xcache_zend_extension_entry
105#endif
106ZEND_DLEXPORT zend_extension zend_extension_entry;
107ZEND_DECLARE_MODULE_GLOBALS(xcache);
108/* }}} */
109
110/* any function in *_dmz is only safe be called within locked(single thread) area */
111
112static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
113{
114    /* this function isn't required but can be in dmz */
115
116    if (a->type != b->type) {
117        return 0;
118    }
119    switch (a->type) {
120        case XC_TYPE_PHP:
121#ifdef HAVE_INODE
122            do {
123                xc_entry_data_php_t *ap = a->data.php;
124                xc_entry_data_php_t *bp = b->data.php;
[165]125                if (ap->inode) {
126                    return ap->inode == bp->inode
127                        && ap->device == bp->device;
128                }
[1]129            } while(0);
130#endif
131            /* fall */
132
133        case XC_TYPE_VAR:
134            do {
135#ifdef IS_UNICODE
136                if (a->name_type == IS_UNICODE) {
137                    if (a->name.ustr.len != b->name.ustr.len) {
138                        return 0;
139                    }
140                    return memcmp(a->name.ustr.val, b->name.ustr.val, (a->name.ustr.len + 1) * sizeof(UChar)) == 0;
141                }
142                else {
143                    return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
144                }
145#else
146                return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
147#endif
148
149            } while(0);
150        default:
151            assert(0);
152    }
153    return 0;
154}
155/* }}} */
[137]156static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */
[1]157{
[148]158    xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce);
[1]159}
160/* }}} */
161static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */
162{
163    xc_entry_t **head = &(xce->cache->entries[xce->hvalue]);
164    xce->next = *head;
165    *head = xce;
[32]166    xce->cache->entries_count ++;
[1]167}
168/* }}} */
169static xc_entry_t *xc_entry_store_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
170{
171    xc_entry_t *stored_xce;
172
173    xce->hits  = 0;
174    xce->ctime = XG(request_time);
175    xce->atime = XG(request_time);
176    stored_xce = xc_processor_store_xc_entry_t(xce TSRMLS_CC);
177    if (stored_xce) {
178        xc_entry_add_dmz(stored_xce);
179        return stored_xce;
180    }
181    else {
182        xce->cache->ooms ++;
183        return NULL;
184    }
185}
186/* }}} */
[137]187static void xc_entry_free_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
[114]188{
189    xce->cache->entries_count --;
190    if (xce->refcount == 0) {
[137]191        xc_entry_free_real_dmz(xce);
[114]192    }
193    else {
194        xce->next = xce->cache->deletes;
195        xce->cache->deletes = xce;
196        xce->dtime = XG(request_time);
197        xce->cache->deletes_count ++;
198    }
199    return;
200}
201/* }}} */
[1]202static void xc_entry_remove_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
203{
[114]204    xc_entry_t **pp = &(xce->cache->entries[xce->hvalue]);
[1]205    xc_entry_t *p;
[114]206    for (p = *pp; p; pp = &(p->next), p = p->next) {
[1]207        if (xc_entry_equal_dmz(xce, p)) {
[137]208            /* unlink */
209            *pp = p->next;
[138]210            xc_entry_free_dmz(xce TSRMLS_CC);
[1]211            return;
212        }
213    }
214    assert(0);
215}
216/* }}} */
217static xc_entry_t *xc_entry_find_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
218{
219    xc_entry_t *p;
220    for (p = xce->cache->entries[xce->hvalue]; p; p = p->next) {
221        if (xc_entry_equal_dmz(xce, p)) {
222            if (p->type == XC_TYPE_VAR || /* PHP */ p->data.php->mtime == xce->data.php->mtime) {
223                p->hits ++;
224                p->atime = XG(request_time);
225                return p;
226            }
227            else {
228                xc_entry_remove_dmz(p TSRMLS_CC);
229                return NULL;
230            }
231        }
232    }
233    return NULL;
234}
235/* }}} */
236static void xc_entry_hold_php_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
237{
[140]238#ifdef DEBUG
239    fprintf(stderr, "hold %s\n", ZSTR_S(xce->name));
240#endif
[1]241    xce->refcount ++;
242    xc_stack_push(&XG(php_holds)[xce->cache->cacheid], (void *)xce);
243}
244/* }}} */
245#if 0
246static void xc_entry_hold_var_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
247{
248    xce->refcount ++;
249    xc_stack_push(&XG(var_holds)[xce->cache->cacheid], (void *)xce);
250}
251/* }}} */
252#endif
253
[114]254/* helper function that loop through each entry */
255#define XC_ENTRY_APPLY_FUNC(name) int name(xc_entry_t *entry TSRMLS_DC)
256typedef XC_ENTRY_APPLY_FUNC((*cache_apply_dmz_func_t));
257static void xc_entry_apply_dmz(xc_cache_t *cache, cache_apply_dmz_func_t apply_func TSRMLS_DC) /* {{{ */
258{
259    xc_entry_t *p, **pp;
260    int i, c;
261
262    for (i = 0, c = cache->hentry->size; i < c; i ++) {
263        pp = &(cache->entries[i]);
[137]264        for (p = *pp; p; p = *pp) {
[114]265            if (apply_func(p TSRMLS_CC)) {
[137]266                /* unlink */
267                *pp = p->next;
[138]268                xc_entry_free_dmz(p TSRMLS_CC);
[114]269            }
270            else {
271                pp = &(p->next);
272            }
273        }
274    }
275}
276/* }}} */
277
278#define XC_CACHE_APPLY_FUNC(name) void name(xc_cache_t *cache TSRMLS_DC)
279/* call graph:
[120]280 * xc_gc_expires_php -> xc_gc_expires_one -> xc_entry_apply_dmz -> xc_gc_expires_php_entry_dmz
281 * xc_gc_expires_var -> xc_gc_expires_one -> xc_entry_apply_dmz -> xc_gc_expires_var_entry_dmz
[114]282 */
[120]283static XC_ENTRY_APPLY_FUNC(xc_gc_expires_php_entry_dmz) /* {{{ */
[114]284{
[116]285#ifdef DEBUG
[114]286    fprintf(stderr, "ttl %d, %d %d\n", XG(request_time), entry->atime, xc_php_ttl);
[116]287#endif
[114]288    if (XG(request_time) > entry->atime + xc_php_ttl) {
289        return 1;
290    }
291    return 0;
292}
293/* }}} */
[120]294static XC_ENTRY_APPLY_FUNC(xc_gc_expires_var_entry_dmz) /* {{{ */
[114]295{
296    if (VAR_ENTRY_EXPIRED(entry)) {
297        return 1;
298    }
299    return 0;
300}
301/* }}} */
302static void xc_gc_expires_one(xc_cache_t *cache, zend_ulong gc_interval, cache_apply_dmz_func_t apply_func TSRMLS_DC) /* {{{ */
303{
[116]304#ifdef DEBUG
[114]305    fprintf(stderr, "interval %d, %d %d\n", XG(request_time), cache->last_gc_expires, gc_interval);
[116]306#endif
[129]307    if (XG(request_time) - cache->last_gc_expires >= gc_interval) {
[114]308        ENTER_LOCK(cache) {
[129]309            if (XG(request_time) - cache->last_gc_expires >= gc_interval) {
[114]310                cache->last_gc_expires = XG(request_time);
311                xc_entry_apply_dmz(cache, apply_func TSRMLS_CC);
312            }
313        } LEAVE_LOCK(cache);
314    }
315}
316/* }}} */
[120]317static void xc_gc_expires_php(TSRMLS_D) /* {{{ */
[114]318{
319    int i, c;
320
321    if (!xc_php_ttl || !xc_php_gc_interval) {
322        return;
323    }
324
325    for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
[120]326        xc_gc_expires_one(xc_php_caches[i], xc_php_gc_interval, xc_gc_expires_php_entry_dmz TSRMLS_CC);
[114]327    }
328}
329/* }}} */
[120]330static void xc_gc_expires_var(TSRMLS_D) /* {{{ */
[114]331{
332    int i, c;
333
334    if (!xc_var_gc_interval) {
335        return;
336    }
337
338    for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
[120]339        xc_gc_expires_one(xc_var_caches[i], xc_var_gc_interval, xc_gc_expires_var_entry_dmz TSRMLS_CC);
[114]340    }
341}
342/* }}} */
343
344static XC_CACHE_APPLY_FUNC(xc_gc_delete_dmz) /* {{{ */
345{
346    xc_entry_t *p, **pp;
347
348    pp = &cache->deletes;
[141]349    for (p = *pp; p; p = *pp) {
[114]350        if (XG(request_time) - p->dtime > 3600) {
351            p->refcount = 0;
352            /* issue warning here */
353        }
354        if (p->refcount == 0) {
[137]355            /* unlink */
[114]356            *pp = p->next;
357            cache->deletes_count --;
[137]358            xc_entry_free_real_dmz(p);
[114]359        }
360        else {
361            pp = &(p->next);
362        }
363    }
364}
365/* }}} */
366static XC_CACHE_APPLY_FUNC(xc_gc_deletes_one) /* {{{ */
367{
368    if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
369        ENTER_LOCK(cache) {
370            if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
[136]371                cache->last_gc_deletes = XG(request_time);
[114]372                xc_gc_delete_dmz(cache TSRMLS_CC);
373            }
374        } LEAVE_LOCK(cache);
375    }
376}
377/* }}} */
378static void xc_gc_deletes(TSRMLS_D) /* {{{ */
379{
380    int i, c;
381
382    for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
383        xc_gc_deletes_one(xc_php_caches[i] TSRMLS_CC);
384    }
385
386    for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
387        xc_gc_deletes_one(xc_var_caches[i] TSRMLS_CC);
388    }
389}
390/* }}} */
391
[1]392/* helper functions for user functions */
[118]393static void xc_fillinfo_dmz(int cachetype, xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
[1]394{
395    zval *blocks;
396    const xc_block_t *b;
397#ifndef NDEBUG
398    xc_memsize_t avail = 0;
399#endif
400    xc_mem_t *mem = cache->mem;
[148]401    const xc_mem_handlers_t *handlers = mem->handlers;
[129]402    zend_ulong interval = (cachetype == XC_TYPE_PHP) ? xc_php_gc_interval : xc_var_gc_interval;
[1]403
404    add_assoc_long_ex(return_value, ZEND_STRS("slots"),     cache->hentry->size);
405    add_assoc_long_ex(return_value, ZEND_STRS("compiling"), cache->compiling);
406    add_assoc_long_ex(return_value, ZEND_STRS("misses"),    cache->misses);
407    add_assoc_long_ex(return_value, ZEND_STRS("hits"),      cache->hits);
408    add_assoc_long_ex(return_value, ZEND_STRS("clogs"),     cache->clogs);
409    add_assoc_long_ex(return_value, ZEND_STRS("ooms"),      cache->ooms);
410
[114]411    add_assoc_long_ex(return_value, ZEND_STRS("cached"),    cache->entries_count);
412    add_assoc_long_ex(return_value, ZEND_STRS("deleted"),   cache->deletes_count);
[118]413    if (interval) {
414        add_assoc_long_ex(return_value, ZEND_STRS("gc"),    (cache->last_gc_expires + interval) - XG(request_time));
415    }
416    else {
417        add_assoc_null_ex(return_value, ZEND_STRS("gc"));
418    }
[1]419
420    MAKE_STD_ZVAL(blocks);
421    array_init(blocks);
422
[148]423    add_assoc_long_ex(return_value, ZEND_STRS("size"),  handlers->size(mem));
424    add_assoc_long_ex(return_value, ZEND_STRS("avail"), handlers->avail(mem));
[1]425    add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection);
426
[148]427    for (b = handlers->freeblock_first(mem); b; b = handlers->freeblock_next(b)) {
[1]428        zval *bi;
429
430        MAKE_STD_ZVAL(bi);
431        array_init(bi);
432
[148]433        add_assoc_long_ex(bi, ZEND_STRS("size"),   handlers->block_size(b));
434        add_assoc_long_ex(bi, ZEND_STRS("offset"), handlers->block_offset(mem, b));
[1]435        add_next_index_zval(blocks, bi);
436#ifndef NDEBUG
[148]437        avail += handlers->block_size(b);
[1]438#endif
439    }
440    add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks);
[148]441    assert(avail == handlers->avail(mem));
[1]442}
443/* }}} */
444static void xc_fillentry_dmz(xc_entry_t *entry, int del, zval *list TSRMLS_DC) /* {{{ */
445{
446    zval* ei;
447    xc_entry_data_php_t *php;
448    xc_entry_data_var_t *var;
449
450    ALLOC_INIT_ZVAL(ei);
451    array_init(ei);
452
453    add_assoc_long_ex(ei, ZEND_STRS("size"),     entry->size);
454    add_assoc_long_ex(ei, ZEND_STRS("refcount"), entry->refcount);
455    add_assoc_long_ex(ei, ZEND_STRS("hits"),     entry->hits);
456    add_assoc_long_ex(ei, ZEND_STRS("ctime"),    entry->ctime);
457    add_assoc_long_ex(ei, ZEND_STRS("atime"),    entry->atime);
[146]458    if (del) {
459        add_assoc_long_ex(ei, ZEND_STRS("dtime"), entry->dtime);
460    }
[1]461#ifdef IS_UNICODE
462    do {
463        zval *zv;
464        ALLOC_INIT_ZVAL(zv);
465        switch (entry->name_type) {
466            case IS_UNICODE:
467                    ZVAL_UNICODEL(zv, entry->name.ustr.val, entry->name.ustr.len, 1);
468                break;
469            case IS_STRING:
470                ZVAL_STRINGL(zv, entry->name.str.val, entry->name.str.len, 1);
471                break;
472            default:
473                assert(0);
474        }
475        zv->type = entry->name_type;
476        add_assoc_zval_ex(ei, ZEND_STRS("name"), zv);
477    } while (0);
478#else
[96]479    add_assoc_stringl_ex(ei, ZEND_STRS("name"), entry->name.str.val, entry->name.str.len, 1);
[1]480#endif
481    switch (entry->type) {
482        case XC_TYPE_PHP:
483            php = entry->data.php;
[95]484            add_assoc_long_ex(ei, ZEND_STRS("sourcesize"),    php->sourcesize);
[1]485#ifdef HAVE_INODE
[95]486            add_assoc_long_ex(ei, ZEND_STRS("device"),        php->device);
487            add_assoc_long_ex(ei, ZEND_STRS("inode"),         php->inode);
[1]488#endif
[95]489            add_assoc_long_ex(ei, ZEND_STRS("mtime"),         php->mtime);
[1]490
[95]491#ifdef HAVE_XCACHE_CONSTANT
492            add_assoc_long_ex(ei, ZEND_STRS("constinfo_cnt"), php->constinfo_cnt);
493#endif
494            add_assoc_long_ex(ei, ZEND_STRS("function_cnt"),  php->funcinfo_cnt);
495            add_assoc_long_ex(ei, ZEND_STRS("class_cnt"),     php->classinfo_cnt);
[1]496            break;
497        case XC_TYPE_VAR:
498            var = entry->data.var;
499            break;
500
501        default:
502            assert(0);
503    }
504
505    add_next_index_zval(list, ei);
506}
507/* }}} */
508static void xc_filllist_dmz(xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
509{
510    zval* list;
511    int i, c;
512    xc_entry_t *e;
513
514    ALLOC_INIT_ZVAL(list);
515    array_init(list);
516
517    for (i = 0, c = cache->hentry->size; i < c; i ++) {
518        for (e = cache->entries[i]; e; e = e->next) {
[11]519            xc_fillentry_dmz(e, 0, list TSRMLS_CC);
[1]520        }
521    }
522    add_assoc_zval(return_value, "cache_list", list);
523
524    ALLOC_INIT_ZVAL(list);
525    array_init(list);
526    for (e = cache->deletes; e; e = e->next) {
[11]527        xc_fillentry_dmz(e, 1, list TSRMLS_CC);
[1]528    }
529    add_assoc_zval(return_value, "deleted_list", list);
530}
531/* }}} */
532
533static zend_op_array *xc_entry_install(xc_entry_t *xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
534{
535    zend_uint i;
536    xc_entry_data_php_t *p = xce->data.php;
537#ifndef ZEND_ENGINE_2
538    /* new ptr which is stored inside CG(class_table) */
539    xc_cest_t **new_cest_ptrs = (xc_cest_t **)do_alloca(sizeof(xc_cest_t*) * p->classinfo_cnt);
540#endif
541
[95]542#ifdef HAVE_XCACHE_CONSTANT
543    /* install constant */
544    for (i = 0; i < p->constinfo_cnt; i ++) {
545        xc_constinfo_t *ci = &p->constinfos[i];
546        xc_install_constant(xce->name.str.val, &ci->constant,
547                UNISW(0, ci->type), ci->key, ci->key_size TSRMLS_CC);
548    }
549#endif
550
[1]551    /* install function */
552    for (i = 0; i < p->funcinfo_cnt; i ++) {
553        xc_funcinfo_t  *fi = &p->funcinfos[i];
554        xc_install_function(xce->name.str.val, &fi->func,
555                UNISW(0, fi->type), fi->key, fi->key_size TSRMLS_CC);
556    }
557
558    /* install class */
559    for (i = 0; i < p->classinfo_cnt; i ++) {
560        xc_classinfo_t *ci = &p->classinfos[i];
561#ifndef ZEND_ENGINE_2
562        zend_class_entry *ce = CestToCePtr(ci->cest);
563        /* fix pointer to the be which inside class_table */
564        if (ce->parent) {
565            zend_uint class_idx = (/* class_num */ (int) ce->parent) - 1;
566            assert(class_idx < i);
567            ci->cest.parent = new_cest_ptrs[class_idx];
568        }
569        new_cest_ptrs[i] =
570#endif
571        xc_install_class(xce->name.str.val, &ci->cest,
572                UNISW(0, ci->type), ci->key, ci->key_size TSRMLS_CC);
573    }
574
575    i = 1;
576    zend_hash_add(&EG(included_files), xce->name.str.val, xce->name.str.len+1, (void *)&i, sizeof(int), NULL);
[131]577    if (h) {
578        zend_llist_add_element(&CG(open_files), h);
579    }
[1]580
581#ifndef ZEND_ENGINE_2
582    free_alloca(new_cest_ptrs);
583#endif
584    return p->op_array;
585}
586/* }}} */
587
[11]588static inline void xc_entry_unholds_real(xc_stack_t *holds, xc_cache_t **caches, int cachecount TSRMLS_DC) /* {{{ */
[1]589{
590    int i;
591    xc_stack_t *s;
592    xc_cache_t *cache;
593    xc_entry_t *xce;
594
595    for (i = 0; i < cachecount; i ++) {
596        s = &holds[i];
[140]597#ifdef DEBUG
598        fprintf(stderr, "holded %d\n", xc_stack_size(s));
599#endif
[1]600        if (xc_stack_size(s)) {
601            cache = ((xc_entry_t *)xc_stack_top(s))->cache;
602            ENTER_LOCK(cache) {
[140]603                while (xc_stack_size(s)) {
604                    xce = (xc_entry_t*) xc_stack_pop(s);
605#ifdef DEBUG
606                    fprintf(stderr, "unhold %s\n", ZSTR_S(xce->name));
607#endif
[1]608                    xce->refcount --;
609                    assert(xce->refcount >= 0);
610                }
611            } LEAVE_LOCK(cache);
612        }
613    }
614}
615/* }}} */
616static void xc_entry_unholds(TSRMLS_D) /* {{{ */
617{
[11]618    xc_entry_unholds_real(XG(php_holds), xc_php_caches, xc_php_hcache.size TSRMLS_CC);
619    xc_entry_unholds_real(XG(var_holds), xc_var_caches, xc_var_hcache.size TSRMLS_CC);
[1]620}
621/* }}} */
[11]622static int xc_stat(const char *filename, const char *include_path, struct stat *pbuf TSRMLS_DC) /* {{{ */
[1]623{
[165]624    char filepath[MAXPATHLEN];
[1]625    char *paths, *path;
626    char *tokbuf;
627    int size = strlen(include_path) + 1;
628    char tokens[] = { DEFAULT_DIR_SEPARATOR, '\0' };
629
630    paths = (char *)do_alloca(size);
631    memcpy(paths, include_path, size);
632
[11]633    for (path = php_strtok_r(paths, tokens, &tokbuf); path; path = php_strtok_r(NULL, tokens, &tokbuf)) {
[165]634        if (snprintf(filepath, sizeof(filepath), "%s/%s", path, filename) >= MAXPATHLEN - 1) {
[1]635            continue;
636        }
637        if (VCWD_STAT(filepath, pbuf) == 0) {
638            free_alloca(paths);
639            return 0;
640        }
641    }
642
643    free_alloca(paths);
644
645    return 1;
646}
647/* }}} */
648
649#define HASH(i) (i)
650#define HASH_USTR_L(t, s, l) HASH(zend_u_inline_hash_func(t, s, (l + 1) * sizeof(UChar)))
651#define HASH_STR_L(s, l) HASH(zend_inline_hash_func(s, l + 1))
652#define HASH_STR(s) HASH_STR_L(s, strlen(s) + 1)
653#define HASH_NUM(n) HASH(n)
[165]654static inline xc_hash_value_t xc_entry_hash_name(xc_entry_t *xce TSRMLS_DC) /* {{{ */
[1]655{
[103]656    return UNISW(NOTHING, UG(unicode) ? HASH_USTR_L(xce->name_type, xce->name.uni.val, xce->name.uni.len) :)
[1]657        HASH_STR_L(xce->name.str.val, xce->name.str.len);
658}
659/* }}} */
[165]660#define xc_entry_hash_var xc_entry_hash_name
[152]661static inline xc_hash_value_t xc_entry_hash_php(xc_entry_t *xce TSRMLS_DC) /* {{{ */
[1]662{
663#ifdef HAVE_INODE
[165]664    if (xce->data.php->inode) {
665        return HASH(xce->data.php->device + xce->data.php->inode);
666    }
[1]667#endif
[165]668    return xc_entry_hash_name(xce TSRMLS_CC);
[1]669}
670/* }}} */
[165]671static int xc_entry_init_key_php(xc_entry_t *xce, char *filename, char *opened_path_buffer TSRMLS_DC) /* {{{ */
[1]672{
673    struct stat buf, *pbuf;
674    xc_hash_value_t hv;
675    int cacheid;
676    xc_entry_data_php_t *php;
[75]677    char *ptr;
[1]678
679    if (!filename || !SG(request_info).path_translated) {
680        return 0;
681    }
682
[165]683    php = xce->data.php;
684
685    if (XG(stat)) {
[1]686        if (strcmp(SG(request_info).path_translated, filename) == 0) {
687            /* sapi has already done this stat() for us */
688            pbuf = sapi_get_stat(TSRMLS_C);
689            if (pbuf) {
[165]690                goto stat_done;
[1]691            }
692        }
693
[75]694        /* absolute path */
[1]695        pbuf = &buf;
696        if (IS_ABSOLUTE_PATH(filename, strlen(filename))) {
697            if (VCWD_STAT(filename, pbuf) != 0) {
698                return 0;
699            }
[165]700            goto stat_done;
[1]701        }
[75]702
703        /* relative path */
704        if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) {
705            ptr = filename + 1;
706            if (*ptr == '.') {
707                while (*(++ptr) == '.');
708                if (!IS_SLASH(*ptr)) {
709                    goto not_relative_path;
710                }   
711            }
712
713            if (VCWD_STAT(filename, pbuf) != 0) {
[1]714                return 0;
715            }
[165]716            goto stat_done;
[1]717        }
[75]718not_relative_path:
719
720        /* use include_path */
721        if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != 0) {   
722            return 0;
723        }
[1]724
[165]725        /* fall */
726
727stat_done:
728        if (XG(request_time) - pbuf->st_mtime < 2) {
729            return 0;
730        }
731
732        php->mtime        = pbuf->st_mtime;
733#ifdef HAVE_INODE
734        php->device       = pbuf->st_dev;
735        php->inode        = pbuf->st_ino;
736#endif
737        php->sourcesize   = pbuf->st_size;
[1]738    }
[165]739    else { /* XG(inode) */
740        php->mtime        = 0;
741#ifdef HAVE_INODE
742        php->device       = 0;
743        php->inode        = 0;
744#endif
745        php->sourcesize   = 0;
746    }
[1]747
[165]748#ifdef HAVE_INODE
749    if (!php->inode)
750#endif
751    {
752        /* hash on filename, let's expand it to real path */
753        filename = expand_filepath(filename, opened_path_buffer TSRMLS_CC);
754        if (filename == NULL) {
755            return 0;
756        }
757    }
758
[19]759    UNISW(NOTHING, xce->name_type = IS_STRING;)
[1]760    xce->name.str.val = filename;
761    xce->name.str.len = strlen(filename);
762
[152]763    hv = xc_entry_hash_php(xce TSRMLS_CC);
[1]764    cacheid = (hv & xc_php_hcache.mask);
765    xce->cache = xc_php_caches[cacheid];
766    hv >>= xc_php_hcache.bits;
767    xce->hvalue = (hv & xc_php_hentry.mask);
768
769    xce->type = XC_TYPE_PHP;
770    return 1;
771}
772/* }}} */
773static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
774{
775    xc_sandbox_t sandbox;
776    zend_op_array *op_array;
777    xc_entry_t xce, *stored_xce;
778    xc_entry_data_php_t php;
779    xc_cache_t *cache;
780    zend_bool clogged = 0;
781    zend_bool catched = 0;
782    char *filename;
[165]783    char opened_path_buffer[MAXPATHLEN];
[95]784    int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
[1]785
786    if (!xc_initized) {
787        assert(0);
788    }
789
790    if (!XG(cacher)) {
791        op_array = origin_compile_file(h, type TSRMLS_CC);
792#ifdef HAVE_XCACHE_OPTIMIZER
793        if (XG(optimizer)) {
794            xc_optimize(op_array TSRMLS_CC);
795        }
796#endif
797        return op_array;
798    }
799
800    /* {{{ prepare key
801     * include_once() and require_once() gives us opened_path
802     * however, include() and require() non-absolute path which break
803     * included_files, and may confuse with (include|require)_once
804     * -- Xuefer
805     */
806
807    filename = h->opened_path ? h->opened_path : h->filename;
808    xce.data.php = &php;
[165]809    if (!xc_entry_init_key_php(&xce, filename, opened_path_buffer TSRMLS_CC)) {
[1]810        return origin_compile_file(h, type TSRMLS_CC);
811    }
812    cache = xce.cache;
813    /* }}} */
814    /* {{{ restore */
815    /* stale precheck */
816    if (cache->compiling) {
817        cache->clogs ++; /* is it safe here? */
818        return origin_compile_file(h, type TSRMLS_CC);
819    }
820
821    stored_xce = NULL;
822    op_array = NULL;
[130]823    ENTER_LOCK_EX(cache) {
[1]824        /* clogged */
825        if (cache->compiling) {
826            cache->clogs ++;
827            op_array = NULL;
828            clogged = 1;
829            break;
830        }
831
832        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
833        /* found */
834        if (stored_xce) {
835#ifdef DEBUG
836            fprintf(stderr, "found %s, catch it\n", stored_xce->name.str.val);
837#endif
838            xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
839            cache->hits ++;
840            break;
841        }
842
843        cache->compiling = XG(request_time);
844        cache->misses ++;
[130]845    } LEAVE_LOCK_EX(cache);
[1]846
[130]847    if (catched) {
848        cache->compiling = 0;
849        zend_bailout();
850    }
851
[1]852    /* found */
853    if (stored_xce) {
854        goto restore;
855    }
856
857    /* clogged */
858    if (clogged) {
859        return origin_compile_file(h, type TSRMLS_CC);
860    }
861    /* }}} */
862
863    /* {{{ compile */
864#ifdef DEBUG
865    fprintf(stderr, "compiling %s\n", filename);
866#endif
867
868    /* make compile inside sandbox */
869    xc_sandbox_init(&sandbox, filename TSRMLS_CC);
870
[95]871    old_classinfo_cnt = zend_hash_num_elements(CG(class_table));
872    old_funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
873    old_constinfo_cnt  = zend_hash_num_elements(EG(zend_constants));
874
[1]875    zend_try {
876        op_array = origin_compile_file(h, type TSRMLS_CC);
877    } zend_catch {
878        catched = 1;
879    } zend_end_try();
880
881    if (catched) {
882        goto err_bailout;
883    }
884
885    if (op_array == NULL) {
886        goto err_oparray;
887    }
888
[86]889    filename = h->opened_path ? h->opened_path : h->filename;
[165]890    /* none-inode enabled entry hash/compare on name
891     * do not update to its name to real pathname
892     */
893#ifdef HAVE_INODE
894    if (xce.data.php->inode)
895#endif
896    {
897        if (xce.name.str.val != filename) {
898            xce.name.str.val = filename;
899            xce.name.str.len = strlen(filename);
900        }
[86]901    }
902
[1]903#ifdef HAVE_XCACHE_OPTIMIZER
904    if (XG(optimizer)) {
905        xc_optimize(op_array TSRMLS_CC);
906    }
907#endif
908
909    php.op_array      = op_array;
910
[95]911#ifdef HAVE_XCACHE_CONSTANT
912    php.constinfo_cnt = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
913#endif
914    php.funcinfo_cnt  = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
915    php.classinfo_cnt = zend_hash_num_elements(CG(class_table))    - old_classinfo_cnt;
[1]916
[95]917#define X_ALLOC_N(var, cnt) do {     \
918    if (php.cnt) {                   \
919        ECALLOC_N(php.var, php.cnt); \
920        if (!php.var) {              \
921            goto err_##var;          \
922        }                            \
923    }                                \
924    else {                           \
925        php.var = NULL;              \
926    }                                \
927} while (0)
928
929#ifdef HAVE_XCACHE_CONSTANT
930    X_ALLOC_N(constinfos, constinfo_cnt);
931#endif
932    X_ALLOC_N(funcinfos,  funcinfo_cnt);
933    X_ALLOC_N(classinfos, classinfo_cnt);
934#undef X_ALLOC
[1]935    /* }}} */
936    /* {{{ shallow copy, pointers only */ {
937        Bucket *b;
938        unsigned int i;
939
[95]940#define COPY_H(vartype, var, cnt, name, datatype) do {        \
941    for (i = 0; b; i ++, b = b->pListNext) {                  \
942        vartype *data = &php.var[i];                          \
943                                                              \
944        if (i < old_##cnt) {                                  \
945            continue;                                         \
946        }                                                     \
947                                                              \
948        assert(i < old_##cnt + php.cnt);                      \
949        assert(b->pData);                                     \
950        memcpy(&data->name, b->pData, sizeof(datatype));      \
951        UNISW(NOTHING, data->type = b->key.type;)             \
[103]952        if (UNISW(1, b->key.type == IS_STRING)) {             \
953            ZSTR_S(data->key)      = BUCKET_KEY(b);           \
954        }                                                     \
955        else {                                                \
956            ZSTR_U(data->key)      = BUCKET_UKEY(b);          \
957        }                                                     \
[95]958        data->key_size   = b->nKeyLength;                     \
959    }                                                         \
960} while(0)
[1]961
[95]962#ifdef HAVE_XCACHE_CONSTANT
963        b = EG(zend_constants)->pListHead; COPY_H(xc_constinfo_t, constinfos, constinfo_cnt, constant, zend_constant);
964#endif
965        b = CG(function_table)->pListHead; COPY_H(xc_funcinfo_t,  funcinfos,  funcinfo_cnt,  func,     zend_function);
966        b = CG(class_table)->pListHead;    COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest,     xc_cest_t);
[1]967
[95]968#undef COPY_H
969        /* for ZE1, cest need to fix inside store */
[1]970    }
971    /* }}} */
[130]972    ENTER_LOCK_EX(cache) { /* {{{ store/add entry */
[1]973        stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
[130]974    } LEAVE_LOCK_EX(cache);
[1]975    /* }}} */
976#ifdef DEBUG
977    fprintf(stderr, "stored\n");
978#endif
979
[95]980#define X_FREE(var) \
981    if (xce.data.php->var) { \
982        efree(xce.data.php->var); \
983    } \
984err_##var:
985
986    X_FREE(classinfos)
987    X_FREE(funcinfos)
988#ifdef HAVE_XCACHE_CONSTANT
989    X_FREE(constinfos)
990#endif
991#undef X_FREE
992
[1]993err_oparray:
994err_bailout:
995
996    if (xc_test && stored_xce) {
[131]997        /* free it, no install. restore now */
[1]998        xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
999    }
1000    else {
1001        xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
1002    }
1003
1004    ENTER_LOCK(cache) {
1005        cache->compiling = 0;
1006    } LEAVE_LOCK(cache);
1007    if (catched) {
1008        zend_bailout();
1009    }
1010    if (xc_test && stored_xce) {
[132]1011#ifdef ZEND_ENGINE_2
[119]1012        destroy_op_array(op_array TSRMLS_CC);
[132]1013#else
1014        destroy_op_array(op_array);
1015#endif
[119]1016        efree(op_array);
[131]1017        h = NULL;
[1]1018        goto restore;
1019    }
1020    return op_array;
1021
1022restore:
[86]1023    if (php_check_open_basedir(stored_xce->name.str.val TSRMLS_CC) != 0) {
1024        return NULL;
1025    }
1026
[1]1027#ifdef DEBUG
1028    fprintf(stderr, "restoring\n");
1029#endif
1030    xc_processor_restore_xc_entry_t(&xce, stored_xce, xc_readonly_protection TSRMLS_CC);
1031
[95]1032    catched = 0;
1033    zend_try {
1034        op_array = xc_entry_install(&xce, h TSRMLS_CC);
1035    } zend_catch {
1036        catched = 1;
1037    } zend_end_try();
1038
1039#define X_FREE(var) \
1040    if (xce.data.php->var) { \
1041        efree(xce.data.php->var); \
1042    }
1043    X_FREE(classinfos)
1044    X_FREE(funcinfos)
1045#ifdef HAVE_XCACHE_CONSTANT
1046    X_FREE(constinfos)
1047#endif
1048#undef X_FREE
[1]1049    efree(xce.data.php);
[95]1050
1051    if (catched) {
1052        zend_bailout();
1053    }
[1]1054#ifdef DEBUG
1055    fprintf(stderr, "restored\n");
1056#endif
1057    return op_array;
1058}
1059/* }}} */
1060
1061/* gdb helper functions, but N/A for coredump */
1062int xc_is_rw(const void *p) /* {{{ */
1063{
[148]1064    xc_shm_t *shm;
[1]1065    int i;
1066    if (!xc_initized) {
1067        return 0;
1068    }
1069    for (i = 0; i < xc_php_hcache.size; i ++) {
[148]1070        shm = xc_php_caches[i]->shm;
1071        if (shm->handlers->is_readwrite(shm, p)) {
[1]1072            return 1;
1073        }
1074    }
1075    for (i = 0; i < xc_var_hcache.size; i ++) {
[148]1076        shm = xc_var_caches[i]->shm;
1077        if (shm->handlers->is_readwrite(shm, p)) {
[1]1078            return 1;
1079        }
1080    }
1081    return 0;
1082}
1083/* }}} */
1084int xc_is_ro(const void *p) /* {{{ */
1085{
[148]1086    xc_shm_t *shm;
[1]1087    int i;
1088    if (!xc_initized) {
1089        return 0;
1090    }
1091    for (i = 0; i < xc_php_hcache.size; i ++) {
[148]1092        shm = xc_php_caches[i]->shm;
1093        if (shm->handlers->is_readonly(shm, p)) {
[1]1094            return 1;
1095        }
1096    }
1097    for (i = 0; i < xc_var_hcache.size; i ++) {
[148]1098        shm = xc_var_caches[i]->shm;
1099        if (shm->handlers->is_readonly(shm, p)) {
[1]1100            return 1;
1101        }
1102    }
1103    return 0;
1104}
1105/* }}} */
1106int xc_is_shm(const void *p) /* {{{ */
1107{
1108    return xc_is_ro(p) || xc_is_rw(p);
1109}
1110/* }}} */
1111
1112/* module helper function */
1113static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
1114{
[11]1115    typedef struct {
[1]1116        const char *prefix;
[20]1117        zend_uchar (*getsize)();
[1]1118        const char *(*get)(zend_uchar i);
[11]1119    } xc_meminfo_t;
1120    xc_meminfo_t nameinfos[] = {
[1]1121        { "",        xc_get_op_type_count,   xc_get_op_type   },
1122        { "",        xc_get_data_type_count, xc_get_data_type },
1123        { "",        xc_get_opcode_count,    xc_get_opcode    },
1124        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
1125        { NULL, NULL, NULL }
1126    };
[11]1127    xc_meminfo_t* p;
[20]1128    zend_uchar i, count;
[1]1129    char const_name[96];
1130    int const_name_len;
1131    int undefdone = 0;
1132
1133    for (p = nameinfos; p->getsize; p ++) {
[20]1134        count = p->getsize();
1135        for (i = 0; i < count; i ++) {
[1]1136            const char *name = p->get(i);
1137            if (!name) continue;
1138            if (strcmp(name, "UNDEF") == 0) {
1139                if (undefdone) continue;
1140                undefdone = 1;
1141            }
1142            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
1143            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1144        }
1145    }
1146
1147    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1148    zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1149    zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
[119]1150    zend_register_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1151    zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
[1]1152    return 0;
1153}
1154/* }}} */
[11]1155static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
[1]1156{
1157    int i;
1158    xc_cache_t *cache;
1159    xc_shm_t *shm;
1160
1161    if (!caches) {
1162        return NULL;
1163    }
1164    shm = NULL;
1165    for (i = 0; i < hcache->size; i ++) {
1166        cache = caches[i];
1167        if (cache) {
1168            if (cache->lck) {
1169                xc_lock_destroy(cache->lck);
1170            }
1171            /* do NOT free
1172            if (cache->entries) {
[148]1173                cache->mem->handlers->free(cache->mem, cache->entries);
[1]1174            }
[148]1175            cache->mem->handlers->free(cache->mem, cache);
[1]1176            */
[154]1177            shm = cache->shm;
[148]1178            shm->handlers->memdestroy(cache->mem);
[1]1179        }
1180    }
1181    free(caches);
1182    return shm;
1183}
1184/* }}} */
[148]1185static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_shmsize_t shmsize) /* {{{ */
[1]1186{
1187    xc_cache_t **caches = NULL, *cache;
1188    xc_mem_t *mem;
[114]1189    time_t now = time(NULL);
[1]1190    int i;
[49]1191    xc_memsize_t memsize;
[11]1192
[49]1193    memsize = shmsize / hcache->size;
[1]1194
[49]1195    /* Don't let it break out of mem after ALIGNed
1196     * This is important for
1197     * Simply loop until it fit our need
1198     */
1199    while (ALIGN(memsize) * hcache->size > shmsize && ALIGN(memsize) != memsize) {
1200        if (memsize < ALIGN(1)) {
1201            CHECK(NULL, "cache too small");
1202        }
1203        memsize --;
1204    }
1205
[1]1206    CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
1207
1208    for (i = 0; i < hcache->size; i ++) {
[148]1209        CHECK(mem            = shm->handlers->meminit(shm, memsize), "Failed init memory allocator");
1210        CHECK(cache          = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
1211        CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
[1]1212        CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
1213
1214        cache->hcache  = hcache;
1215        cache->hentry  = hentry;
1216        cache->shm     = shm;
1217        cache->mem     = mem;
1218        cache->cacheid = i;
[114]1219        cache->last_gc_deletes = now;
1220        cache->last_gc_expires = now;
[1]1221        caches[i] = cache;
1222    }
1223    return caches;
1224
1225err:
1226    if (caches) {
1227        xc_cache_destroy(caches, hcache);
1228    }
1229    return NULL;
1230}
1231/* }}} */
1232static void xc_destroy() /* {{{ */
1233{
1234    xc_shm_t *shm = NULL;
1235
1236    if (origin_compile_file) {
1237        zend_compile_file = origin_compile_file;
1238        origin_compile_file = NULL;
1239    }
1240
1241    if (xc_php_caches) {
1242        shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
1243        xc_php_caches = NULL;
1244    }
1245    if (xc_var_caches) {
1246        shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
1247        xc_var_caches = NULL;
1248    }
1249    if (shm) {
1250        xc_shm_destroy(shm);
1251    }
1252}
1253/* }}} */
1254static int xc_init(int module_number TSRMLS_DC) /* {{{ */
1255{
1256    xc_shm_t *shm;
1257
[11]1258    xc_php_caches = xc_var_caches = NULL;
1259
[1]1260    if (xc_php_size || xc_var_size) {
[148]1261        CHECK(shm = xc_shm_init(xc_shm_scheme, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection, xc_mmap_path, NULL), "Cannot create shm");
1262        if (!shm->handlers->can_readonly(shm)) {
[1]1263            xc_readonly_protection = 0;
1264        }
1265
1266        if (xc_php_size) {
1267            origin_compile_file = zend_compile_file;
1268            zend_compile_file = xc_compile_file;
1269
[148]1270            CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
[1]1271        }
1272
1273        if (xc_var_size) {
[148]1274            CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache");
[1]1275        }
1276    }
1277    return 1;
1278
1279err:
1280    if (xc_php_caches || xc_var_caches) {
1281        xc_destroy();
1282        /* shm destroied */
1283    }
1284    else if (shm) {
1285        xc_shm_destroy(shm);
1286    }
1287    return 0;
1288}
1289/* }}} */
1290static void xc_request_init(TSRMLS_D) /* {{{ */
1291{
[17]1292    int i;
1293
1294    if (xc_php_hcache.size && !XG(php_holds)) {
1295        XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
1296        for (i = 0; i < xc_php_hcache.size; i ++) {
1297            xc_stack_init(&XG(php_holds[i]));
1298        }
1299    }
1300
1301    if (xc_var_hcache.size && !XG(var_holds)) {
1302        XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
1303        for (i = 0; i < xc_var_hcache.size; i ++) {
1304            xc_stack_init(&XG(var_holds[i]));
1305        }
1306    }
1307
[1]1308    if (XG(cacher)) {
1309#if PHP_API_VERSION <= 20041225
1310        XG(request_time) = time(NULL);
1311#else
1312        XG(request_time) = sapi_get_request_time(TSRMLS_C);
1313#endif
1314    }
[27]1315#ifdef HAVE_XCACHE_COVERAGER
1316    xc_coverager_request_init(TSRMLS_C);
[1]1317#endif
1318}
1319/* }}} */
1320static void xc_request_shutdown(TSRMLS_D) /* {{{ */
1321{
1322    xc_entry_unholds(TSRMLS_C);
[120]1323    xc_gc_expires_php(TSRMLS_C);
1324    xc_gc_expires_var(TSRMLS_C);
[114]1325    xc_gc_deletes(TSRMLS_C);
[27]1326#ifdef HAVE_XCACHE_COVERAGER
1327    xc_coverager_request_shutdown(TSRMLS_C);
[1]1328#endif
1329}
1330/* }}} */
[92]1331/* {{{ PHP_GINIT_FUNCTION(xcache) */
1332static
1333#ifdef PHP_GINIT_FUNCTION
1334PHP_GINIT_FUNCTION(xcache)
1335#else
1336void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
1337#endif
[1]1338{
[92]1339    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
[1]1340}
1341/* }}} */
[92]1342/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
1343static
1344#ifdef PHP_GSHUTDOWN_FUNCTION
1345PHP_GSHUTDOWN_FUNCTION(xcache)
1346#else
1347void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
1348#endif
[1]1349{
1350    int i;
1351
[92]1352    if (xcache_globals->php_holds != NULL) {
[1]1353        for (i = 0; i < xc_php_hcache.size; i ++) {
[92]1354            xc_stack_destroy(&xcache_globals->php_holds[i]);
[1]1355        }
[92]1356        free(xcache_globals->php_holds);
1357        xcache_globals->php_holds = NULL;
[1]1358    }
1359
[92]1360    if (xcache_globals->var_holds != NULL) {
[1]1361        for (i = 0; i < xc_var_hcache.size; i ++) {
[92]1362            xc_stack_destroy(&xcache_globals->var_holds[i]);
[1]1363        }
[92]1364        free(xcache_globals->var_holds);
1365        xcache_globals->var_holds = NULL;
[1]1366    }
1367}
1368/* }}} */
1369
1370/* user functions */
[55]1371static int xcache_admin_auth_check(TSRMLS_D) /* {{{ */
[34]1372{
1373    zval **server = NULL;
1374    zval **user = NULL;
1375    zval **pass = NULL;
1376    char *admin_user = NULL;
1377    char *admin_pass = NULL;
1378    HashTable *ht;
1379
1380    if (cfg_get_string("xcache.admin.user", &admin_user) == FAILURE || !admin_user[0]) {
1381        admin_user = NULL;
1382    }
1383    if (cfg_get_string("xcache.admin.pass", &admin_pass) == FAILURE || !admin_pass[0]) {
1384        admin_pass = NULL;
1385    }
1386
1387    if (admin_user == NULL || admin_pass == NULL) {
1388        php_error_docref(NULL TSRMLS_CC, E_ERROR, "xcache.admin.user and xcache.admin.pass is required");
1389        zend_bailout();
1390    }
1391    if (strlen(admin_pass) != 32) {
1392        php_error_docref(NULL TSRMLS_CC, E_ERROR, "unexpect %d bytes of xcache.admin.pass, expected 32 bytes, the password after md5()", strlen(admin_pass));
1393        zend_bailout();
1394    }
1395
[105]1396#ifdef ZEND_ENGINE_2_1
[113]1397    zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
[105]1398#endif
[34]1399    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != SUCCESS || Z_TYPE_PP(server) != IS_ARRAY) {
1400        php_error_docref(NULL TSRMLS_CC, E_ERROR, "_SERVER is corrupted");
1401        zend_bailout();
1402    }
1403    ht = HASH_OF((*server));
1404
1405    if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
1406        user = NULL;
1407    }
1408    else if (Z_TYPE_PP(user) != IS_STRING) {
1409        user = NULL;
1410    }
1411
1412    if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {
1413        pass = NULL;
1414    }
1415    else if (Z_TYPE_PP(pass) != IS_STRING) {
1416        pass = NULL;
1417    }
1418
1419    if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {
1420        PHP_MD5_CTX context;
1421        char md5str[33];
1422        unsigned char digest[16];
1423
1424        PHP_MD5Init(&context);
[91]1425        PHP_MD5Update(&context, (unsigned char *) Z_STRVAL_PP(pass), Z_STRLEN_PP(pass));
[34]1426        PHP_MD5Final(digest, &context);
1427
1428        md5str[0] = '\0';
1429        make_digest(md5str, digest);
1430        if (strcmp(admin_pass, md5str) == 0) {
1431            return 1;
1432        }
1433    }
1434
1435#define STR "WWW-authenticate: basic realm='XCache Administration'"
1436    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1437#undef STR
1438#define STR "HTTP/1.0 401 Unauthorized"
1439    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1440#undef STR
1441    ZEND_PUTS("XCache Auth Failed. User and Password is case sense\n");
1442
1443    zend_bailout();
1444    return 0;
1445}
1446/* }}} */
1447/* {{{ xcache_admin_operate */
[1]1448typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
[34]1449static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
[1]1450{
1451    long type;
1452    int size;
1453    xc_cache_t **caches, *cache;
1454    long id = 0;
1455
[11]1456    if (!xc_initized) {
1457        php_error_docref(NULL TSRMLS_CC, E_WARNING, "XCache is not initized");
1458        RETURN_FALSE;
1459    }
1460
[34]1461    xcache_admin_auth_check(TSRMLS_C);
1462
[1]1463    if (optype == XC_OP_COUNT) {
1464        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
1465            return;
1466        }
1467    }
1468    else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
1469        return;
1470    }
1471
1472    switch (type) {
1473        case XC_TYPE_PHP:
1474            size = xc_php_hcache.size;
1475            caches = xc_php_caches;
1476            break;
1477
1478        case XC_TYPE_VAR:
1479            size = xc_var_hcache.size;
1480            caches = xc_var_caches;
1481            break;
1482
1483        default:
1484            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
1485            RETURN_FALSE;
1486    }
1487
1488    switch (optype) {
1489        case XC_OP_COUNT:
1490            RETURN_LONG(size)
1491            break;
1492
1493        case XC_OP_INFO:
1494        case XC_OP_LIST:
1495            if (id < 0 || id >= size) {
1496                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1497                RETURN_FALSE;
1498            }
1499
1500            array_init(return_value);
1501
1502            cache = caches[id];
1503            ENTER_LOCK(cache) {
1504                if (optype == XC_OP_INFO) {
[118]1505                    xc_fillinfo_dmz(type, cache, return_value TSRMLS_CC);
[1]1506                }
1507                else {
1508                    xc_filllist_dmz(cache, return_value TSRMLS_CC);
1509                }
1510            } LEAVE_LOCK(cache);
1511            break;
1512        case XC_OP_CLEAR:
1513            {
[141]1514                xc_entry_t *e, *next;
[1]1515                int i, c;
1516
1517                if (id < 0 || id >= size) {
1518                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1519                    RETURN_FALSE;
1520                }
1521
1522                cache = caches[id];
1523                ENTER_LOCK(cache) {
1524                    for (i = 0, c = cache->hentry->size; i < c; i ++) {
[141]1525                        for (e = cache->entries[i]; e; e = next) {
1526                            next = e->next;
[1]1527                            xc_entry_remove_dmz(e TSRMLS_CC);
1528                        }
1529                        cache->entries[i] = NULL;
1530                    }
1531                } LEAVE_LOCK(cache);
[114]1532                xc_gc_deletes(TSRMLS_C);
[1]1533            }
1534            break;
1535
1536        default:
1537            assert(0);
1538    }
1539}
1540/* }}} */
[9]1541/* {{{ proto int xcache_count(int type)
1542   Return count of cache on specified cache type */
[1]1543PHP_FUNCTION(xcache_count)
1544{
[34]1545    xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1546}
1547/* }}} */
[9]1548/* {{{ proto array xcache_info(int type, int id)
1549   Get cache info by id on specified cache type */
[1]1550PHP_FUNCTION(xcache_info)
1551{
[34]1552    xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1553}
1554/* }}} */
[9]1555/* {{{ proto array xcache_list(int type, int id)
1556   Get cache entries list by id on specified cache type */
[1]1557PHP_FUNCTION(xcache_list)
1558{
[34]1559    xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1560}
1561/* }}} */
[9]1562/* {{{ proto array xcache_clear_cache(int type, int id)
1563   Clear cache by id on specified cache type */
[1]1564PHP_FUNCTION(xcache_clear_cache)
1565{
[34]1566    xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1567}
1568/* }}} */
1569
1570static int xc_entry_init_key_var(xc_entry_t *xce, zval *name TSRMLS_DC) /* {{{ */
1571{
1572    xc_hash_value_t hv;
1573    int cacheid;
1574
1575    switch (Z_TYPE_P(name)) {
1576#ifdef IS_UNICODE
1577        case IS_UNICODE:
1578#endif
1579        case IS_STRING:
1580            break;
1581        default:
1582#ifdef IS_UNICODE
1583            convert_to_text(name);
1584#else
1585            convert_to_string(name);
1586#endif
1587    }
1588#ifdef IS_UNICODE
1589    xce->name_type = name->type;
1590#endif
1591    xce->name = name->value;
1592
[152]1593    hv = xc_entry_hash_var(xce TSRMLS_CC);
[1]1594
1595    cacheid = (hv & xc_var_hcache.mask);
1596    xce->cache = xc_var_caches[cacheid];
1597    hv >>= xc_var_hcache.bits;
1598    xce->hvalue = (hv & xc_var_hentry.mask);
1599
1600    xce->type = XC_TYPE_VAR;
1601    return SUCCESS;
1602}
1603/* }}} */
[9]1604/* {{{ proto mixed xcache_get(string name)
1605   Get cached data by specified name */
[1]1606PHP_FUNCTION(xcache_get)
1607{
1608    xc_entry_t xce, *stored_xce;
1609    xc_entry_data_var_t var;
1610    zval *name;
1611
1612    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1613        return;
1614    }
1615    xce.data.var = &var;
1616    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1617
1618    ENTER_LOCK(xce.cache) {
1619        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1620        if (stored_xce) {
[114]1621            if (XG(request_time) <= stored_xce->ctime + stored_xce->ttl) {
[1]1622                xc_processor_restore_zval(return_value, stored_xce->data.var->value TSRMLS_CC);
1623                /* return */
1624                break;
1625            }
1626            else {
[11]1627                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1628            }
1629        }
1630
1631        RETVAL_NULL();
1632    } LEAVE_LOCK(xce.cache);
1633}
1634/* }}} */
[9]1635/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
1636   Store data to cache by specified name */
[1]1637PHP_FUNCTION(xcache_set)
1638{
1639    xc_entry_t xce, *stored_xce;
1640    xc_entry_data_var_t var;
1641    zval *name;
1642    zval *value;
1643
[114]1644    xce.ttl = XG(var_ttl);
1645    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &xce.ttl) == FAILURE) {
[1]1646        return;
1647    }
[114]1648
1649    /* max ttl */
1650    if (xc_var_maxttl && (!xce.ttl || xce.ttl > xc_var_maxttl)) {
1651        xce.ttl = xc_var_maxttl;
1652    }
1653
[1]1654    xce.data.var = &var;
1655    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1656
1657    ENTER_LOCK(xce.cache) {
1658        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1659        if (stored_xce) {
[11]1660            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1661        }
1662        var.value = value;
[11]1663        RETVAL_BOOL(xc_entry_store_dmz(&xce TSRMLS_CC) != NULL ? 1 : 0);
[1]1664    } LEAVE_LOCK(xce.cache);
1665}
1666/* }}} */
[9]1667/* {{{ proto bool  xcache_isset(string name)
1668   Check if an entry exists in cache by specified name */
[1]1669PHP_FUNCTION(xcache_isset)
1670{
1671    xc_entry_t xce, *stored_xce;
1672    xc_entry_data_var_t var;
1673    zval *name;
1674
1675    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1676        return;
1677    }
1678    xce.data.var = &var;
1679    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1680
1681    ENTER_LOCK(xce.cache) {
1682        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1683        if (stored_xce) {
[126]1684            if (!VAR_ENTRY_EXPIRED(stored_xce)) {
[1]1685                RETVAL_TRUE;
1686                /* return */
1687                break;
1688            }
1689            else {
[11]1690                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1691            }
1692        }
1693
1694        RETVAL_FALSE;
1695    } LEAVE_LOCK(xce.cache);
1696}
1697/* }}} */
[9]1698/* {{{ proto bool  xcache_unset(string name)
1699   Unset existing data in cache by specified name */
[1]1700PHP_FUNCTION(xcache_unset)
1701{
1702    xc_entry_t xce, *stored_xce;
1703    xc_entry_data_var_t var;
1704    zval *name;
1705
1706    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1707        return;
1708    }
1709    xce.data.var = &var;
1710    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1711
1712    ENTER_LOCK(xce.cache) {
1713        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1714        if (stored_xce) {
[11]1715            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1716            RETVAL_TRUE;
1717        }
1718        else {
1719            RETVAL_FALSE;
1720        }
1721    } LEAVE_LOCK(xce.cache);
1722}
1723/* }}} */
1724static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
1725{
1726    xc_entry_t xce, *stored_xce;
1727    xc_entry_data_var_t var, *stored_var;
1728    zval *name;
1729    long count = 1;
1730    long value = 0;
1731    zval oldzval;
1732
[114]1733    xce.ttl = XG(var_ttl);
1734    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &xce.ttl) == FAILURE) {
[1]1735        return;
1736    }
[114]1737
1738    /* max ttl */
1739    if (xc_var_maxttl && (!xce.ttl || xce.ttl > xc_var_maxttl)) {
1740        xce.ttl = xc_var_maxttl;
1741    }
1742
[1]1743    xce.data.var = &var;
1744    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1745
1746    ENTER_LOCK(xce.cache) {
1747        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1748        if (stored_xce) {
1749#ifdef DEBUG
1750            fprintf(stderr, "incdec: gotxce %s\n", xce.name.str.val);
1751#endif
1752            /* timeout */
[114]1753            if (VAR_ENTRY_EXPIRED(stored_xce)) {
[1]1754#ifdef DEBUG
1755                fprintf(stderr, "incdec: expired\n");
1756#endif
[11]1757                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1758                stored_xce = NULL;
1759            }
1760            else {
1761                /* do it in place */
[114]1762                stored_var = stored_xce->data.var;
[1]1763                if (Z_TYPE_P(stored_var->value) == IS_LONG) {
[114]1764                    stored_xce->ctime = XG(request_time);
1765                    stored_xce->ttl   = xce.ttl;
[1]1766#ifdef DEBUG
1767                    fprintf(stderr, "incdec: islong\n");
1768#endif
1769                    value = Z_LVAL_P(stored_var->value);
1770                    value += (inc == 1 ? count : - count);
1771                    RETVAL_LONG(value);
1772                    Z_LVAL_P(stored_var->value) = value;
[114]1773                    break; /* leave lock */
[1]1774                }
1775                else {
1776#ifdef DEBUG
1777                    fprintf(stderr, "incdec: notlong\n");
1778#endif
1779                    xc_processor_restore_zval(&oldzval, stored_xce->data.var->value TSRMLS_CC);
1780                    convert_to_long(&oldzval);
1781                    value = Z_LVAL(oldzval);
1782                    zval_dtor(&oldzval);
1783                }
1784            }
1785        }
1786#ifdef DEBUG
1787        else {
1788            fprintf(stderr, "incdec: %s not found\n", xce.name.str.val);
1789        }
1790#endif
1791
1792        value += (inc == 1 ? count : - count);
1793        RETVAL_LONG(value);
1794        var.value = return_value;
[114]1795
[1]1796        if (stored_xce) {
1797            xce.atime = stored_xce->atime;
1798            xce.ctime = stored_xce->ctime;
1799            xce.hits  = stored_xce->hits;
[11]1800            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1801        }
[11]1802        xc_entry_store_dmz(&xce TSRMLS_CC);
[1]1803
1804    } LEAVE_LOCK(xce.cache);
1805}
1806/* }}} */
[9]1807/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
1808   Increase an int counter in cache by specified name, create it if not exists */
[1]1809PHP_FUNCTION(xcache_inc)
1810{
1811    xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1812}
1813/* }}} */
[9]1814/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
1815   Decrease an int counter in cache by specified name, create it if not exists */
[1]1816PHP_FUNCTION(xcache_dec)
1817{
1818    xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1819}
1820/* }}} */
[9]1821/* {{{ proto string xcache_asm(string filename)
1822 */
[1]1823#ifdef HAVE_XCACHE_ASSEMBLER
1824PHP_FUNCTION(xcache_asm)
1825{
1826}
1827#endif
1828/* }}} */
1829#ifdef HAVE_XCACHE_DISASSEMBLER
[9]1830/* {{{ proto array  xcache_dasm_file(string filename)
1831   Disassemble file into opcode array by filename */
[1]1832PHP_FUNCTION(xcache_dasm_file)
1833{
1834    char *filename;
[143]1835    int filename_len;
[1]1836
1837    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1838        return;
1839    }
1840    if (!filename_len) RETURN_FALSE;
1841
1842    xc_dasm_file(return_value, filename TSRMLS_CC);
1843}
1844/* }}} */
[9]1845/* {{{ proto array  xcache_dasm_string(string code)
1846   Disassemble php code into opcode array */
[1]1847PHP_FUNCTION(xcache_dasm_string)
1848{
1849    zval *code;
1850
1851    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
1852        return;
1853    }
1854    xc_dasm_string(return_value, code TSRMLS_CC);
1855}
1856/* }}} */
1857#endif
[9]1858/* {{{ proto string xcache_encode(string filename)
1859   Encode php file into XCache opcode encoded format */
[1]1860#ifdef HAVE_XCACHE_ENCODER
1861PHP_FUNCTION(xcache_encode)
1862{
1863}
1864#endif
1865/* }}} */
[9]1866/* {{{ proto bool xcache_decode_file(string filename)
1867   Decode(load) opcode from XCache encoded format file */
[1]1868#ifdef HAVE_XCACHE_DECODER
[9]1869PHP_FUNCTION(xcache_decode_file)
[1]1870{
1871}
1872#endif
1873/* }}} */
[9]1874/* {{{ proto bool xcache_decode_string(string data)
1875   Decode(load) opcode from XCache encoded format data */
1876#ifdef HAVE_XCACHE_DECODER
1877PHP_FUNCTION(xcache_decode_string)
1878{
1879}
1880#endif
1881/* }}} */
[1]1882/* {{{ xc_call_getter */
1883typedef const char *(xc_name_getter_t)(zend_uchar type);
1884static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
1885{
1886    long spec;
1887    const char *name;
1888
1889    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1890        return;
1891    }
1892    if (spec >= 0 && spec < count) {
[11]1893        name = getter((zend_uchar) spec);
[1]1894        if (name) {
1895            /* RETURN_STRING */
1896            int len = strlen(name);
1897            return_value->value.str.len = len;
1898            return_value->value.str.val = estrndup(name, len);
1899            return_value->type = IS_STRING; 
1900            return;
1901        }
1902    }
1903    RETURN_NULL();
1904}
1905/* }}} */
1906/* {{{ proto string xcache_get_op_type(int op_type) */
1907PHP_FUNCTION(xcache_get_op_type)
1908{
1909    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1910}
1911/* }}} */
1912/* {{{ proto string xcache_get_data_type(int type) */
1913PHP_FUNCTION(xcache_get_data_type)
1914{
1915    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1916}
1917/* }}} */
1918/* {{{ proto string xcache_get_opcode(int opcode) */
1919PHP_FUNCTION(xcache_get_opcode)
1920{
1921    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1922}
1923/* }}} */
1924/* {{{ proto string xcache_get_op_spec(int op_type) */
1925PHP_FUNCTION(xcache_get_op_spec)
1926{
1927    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1928}
1929/* }}} */
[8]1930#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
[1]1931/* {{{ proto string xcache_get_opcode_spec(int opcode) */
1932PHP_FUNCTION(xcache_get_opcode_spec)
1933{
1934    long spec;
1935    const xc_opcode_spec_t *opspec;
1936
1937    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1938        return;
1939    }
[17]1940    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
[11]1941        opspec = xc_get_opcode_spec((zend_uchar) spec);
[1]1942        if (opspec) {
1943            array_init(return_value);
1944            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
1945            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
1946            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
1947            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
1948            return;
1949        }
1950    }
1951    RETURN_NULL();
1952}
1953/* }}} */
[8]1954#endif
[1]1955/* {{{ proto mixed xcache_get_special_value(zval value) */
1956PHP_FUNCTION(xcache_get_special_value)
1957{
1958    zval *value;
1959
1960    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
1961        return;
1962    }
1963
1964    if (value->type == IS_CONSTANT) {
1965        *return_value = *value;
1966        zval_copy_ctor(return_value);
1967        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
1968        return;
1969    }
1970
1971    if (value->type == IS_CONSTANT_ARRAY) {
1972        *return_value = *value;
1973        zval_copy_ctor(return_value);
1974        return_value->type = IS_ARRAY;
1975        return;
1976    }
1977
1978    RETURN_NULL();
1979}
1980/* }}} */
1981/* {{{ proto string xcache_coredump(int op_type) */
1982PHP_FUNCTION(xcache_coredump)
1983{
[9]1984    if (xc_test) {
1985        raise(SIGSEGV);
1986    }
1987    else {
1988        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
1989    }
[1]1990}
1991/* }}} */
1992/* {{{ proto string xcache_is_autoglobal(string name) */
1993PHP_FUNCTION(xcache_is_autoglobal)
1994{
1995    char *name;
[143]1996    int name_len;
[1]1997
1998    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
1999        return;
2000    }
2001
2002    RETURN_BOOL(zend_hash_exists(CG(auto_globals), name, name_len + 1));
2003}
2004/* }}} */
2005static function_entry xcache_functions[] = /* {{{ */
2006{
2007    PHP_FE(xcache_count,             NULL)
2008    PHP_FE(xcache_info,              NULL)
2009    PHP_FE(xcache_list,              NULL)
2010    PHP_FE(xcache_clear_cache,       NULL)
2011    PHP_FE(xcache_coredump,          NULL)
2012#ifdef HAVE_XCACHE_ASSEMBLER
2013    PHP_FE(xcache_asm,               NULL)
2014#endif
2015#ifdef HAVE_XCACHE_DISASSEMBLER
2016    PHP_FE(xcache_dasm_file,         NULL)
2017    PHP_FE(xcache_dasm_string,       NULL)
2018#endif
2019#ifdef HAVE_XCACHE_ENCODER
2020    PHP_FE(xcache_encode,            NULL)
2021#endif
2022#ifdef HAVE_XCACHE_DECODER
[9]2023    PHP_FE(xcache_decode_file,       NULL)
2024    PHP_FE(xcache_decode_string,     NULL)
[1]2025#endif
[27]2026#ifdef HAVE_XCACHE_COVERAGER
2027    PHP_FE(xcache_coverager_decode,  NULL)
[1]2028#endif
2029    PHP_FE(xcache_get_special_value, NULL)
2030    PHP_FE(xcache_get_op_type,       NULL)
2031    PHP_FE(xcache_get_data_type,     NULL)
2032    PHP_FE(xcache_get_opcode,        NULL)
[8]2033#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
[1]2034    PHP_FE(xcache_get_opcode_spec,   NULL)
[8]2035#endif
[1]2036    PHP_FE(xcache_is_autoglobal,     NULL)
2037    PHP_FE(xcache_inc,               NULL)
2038    PHP_FE(xcache_dec,               NULL)
2039    PHP_FE(xcache_get,               NULL)
2040    PHP_FE(xcache_set,               NULL)
2041    PHP_FE(xcache_isset,             NULL)
2042    PHP_FE(xcache_unset,             NULL)
2043    {NULL, NULL,                     NULL}
2044};
2045/* }}} */
2046
[75]2047/* old signal handlers {{{ */
2048typedef void (*xc_sighandler_t)(int);
2049#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
2050#include "foreachcoresig.h"
2051#undef FOREACH_SIG
2052/* }}} */
2053static void xcache_signal_handler(int sig);
2054static void xcache_restore_signal_handler() /* {{{ */
[1]2055{
[75]2056#define FOREACH_SIG(sig) do { \
2057    if (old_##sig##_handler != xcache_signal_handler) { \
2058        signal(sig, old_##sig##_handler); \
2059    } \
2060    else { \
2061        signal(sig, SIG_DFL); \
2062    } \
2063} while (0)
2064#include "foreachcoresig.h"
2065#undef FOREACH_SIG
2066}
2067/* }}} */
2068static void xcache_init_signal_handler() /* {{{ */
2069{
2070#define FOREACH_SIG(sig) \
2071    old_##sig##_handler = signal(sig, xcache_signal_handler)
2072#include "foreachcoresig.h"
2073#undef FOREACH_SIG
2074}
2075/* }}} */
2076static void xcache_signal_handler(int sig) /* {{{ */
2077{
2078    xcache_restore_signal_handler();
[1]2079    if (xc_coredump_dir && xc_coredump_dir[0]) {
2080        chdir(xc_coredump_dir);
2081    }
[65]2082    raise(sig);
[1]2083}
2084/* }}} */
2085
2086/* {{{ PHP_INI */
2087
[164]2088static PHP_INI_MH(xc_OnUpdateDummy)
2089{
2090    return SUCCESS;
2091}
2092
2093static PHP_INI_MH(xc_OnUpdateULong)
2094{
2095    zend_ulong *p = (zend_ulong *) mh_arg1;
2096
2097    *p = (zend_ulong) atoi(new_value);
2098    return SUCCESS;
2099}
2100
[1]2101static PHP_INI_MH(xc_OnUpdateBool)
2102{
2103    zend_bool *p = (zend_bool *)mh_arg1;
2104
2105    if (strncasecmp("on", new_value, sizeof("on"))) {
2106        *p = (zend_bool) atoi(new_value);
2107    }
2108    else {
2109        *p = (zend_bool) 1;
2110    }
2111    return SUCCESS;
2112}
2113
2114static PHP_INI_MH(xc_OnUpdateString)
2115{
2116    char **p = (char**)mh_arg1;
2117    if (*p) {
2118        pefree(*p, 1);
2119    }
2120    *p = pemalloc(strlen(new_value) + 1, 1);
2121    strcpy(*p, new_value);
2122    return SUCCESS;
2123}
[82]2124
[114]2125#ifndef ZEND_ENGINE_2
2126#define OnUpdateLong OnUpdateInt
[1]2127#endif
2128
[21]2129#ifdef ZEND_WIN32
2130#   define DEFAULT_PATH "xcache"
2131#else
2132#   define DEFAULT_PATH "/dev/zero"
2133#endif
[1]2134PHP_INI_BEGIN()
[21]2135    PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
[1]2136    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
2137    PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
2138    PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
[164]2139    /* opcode cache */
2140    PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2141    PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2142    PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2143    PHP_INI_ENTRY1     ("xcache.shm_scheme",          "mmap", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_shm_scheme)
2144    PHP_INI_ENTRY1     ("xcache.ttl",                    "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_ttl)
2145    PHP_INI_ENTRY1     ("xcache.gc_interval",            "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_gc_interval)
2146    /* var cache */
2147    PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2148    PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2149    PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2150    PHP_INI_ENTRY1     ("xcache.var_maxttl",             "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_maxttl)
2151    PHP_INI_ENTRY1     ("xcache.var_gc_interval",      "120", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_gc_interval)
[1]2152
2153    STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
[165]2154    STD_PHP_INI_BOOLEAN("xcache.stat",                   "1", PHP_INI_ALL,    OnUpdateBool,        stat,              zend_xcache_globals, xcache_globals)
[1]2155#ifdef HAVE_XCACHE_OPTIMIZER
2156    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
2157#endif
[164]2158    STD_PHP_INI_BOOLEAN("xcache.var_ttl",                "0", PHP_INI_ALL,    OnUpdateLong,        var_ttl,           zend_xcache_globals, xcache_globals)
[27]2159#ifdef HAVE_XCACHE_COVERAGER
[39]2160    PHP_INI_ENTRY1     ("xcache.coveragedump_directory", "/tmp/pcov/", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coveragedump_dir)
2161    STD_PHP_INI_BOOLEAN("xcache.coveragedumper" ,                 "0", PHP_INI_ALL,    OnUpdateBool,        coveragedumper,    zend_xcache_globals, xcache_globals)
[1]2162#endif
2163PHP_INI_END()
2164/* }}} */
2165/* {{{ PHP_MINFO_FUNCTION(xcache) */
2166static PHP_MINFO_FUNCTION(xcache)
2167{
[82]2168    char buf[100];
2169    char *ptr;
[163]2170    int left, len;
2171    xc_shm_scheme_t *scheme;
[82]2172
[1]2173    php_info_print_table_start();
[148]2174    php_info_print_table_header(2, "XCache Support", "enabled");
[1]2175    php_info_print_table_row(2, "Version", XCACHE_VERSION);
[26]2176    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
[1]2177    php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
[82]2178
2179    if (xc_php_size) {
2180        ptr = _php_math_number_format(xc_php_size, 0, '.', ',');
[163]2181        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_php_hcache.size, xc_php_hentry.size);
[82]2182        php_info_print_table_row(2, "Opcode Cache", buf);
2183        efree(ptr);
2184    }
2185    else {
2186        php_info_print_table_row(2, "Opcode Cache", "disabled");
2187    }
2188    if (xc_var_size) {
2189        ptr = _php_math_number_format(xc_var_size, 0, '.', ',');
[163]2190        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_var_hcache.size, xc_var_hentry.size);
[82]2191        php_info_print_table_row(2, "Variable Cache", buf);
2192        efree(ptr);
2193    }
2194    else {
2195        php_info_print_table_row(2, "Variable Cache", "disabled");
2196    }
[163]2197
2198    left = sizeof(buf);
2199    ptr = buf;
2200    buf[0] = '\0';
2201    for (scheme = xc_shm_scheme_first(); scheme; scheme = xc_shm_scheme_next(scheme)) {
2202        len = snprintf(ptr, left, ptr == buf ? "%s" : ", %s", xc_shm_scheme_name(scheme));
2203        left -= len;
2204        ptr += len;
2205    }
2206    php_info_print_table_row(2, "Shared Memory Schemes", buf);
2207
[26]2208#ifdef HAVE_XCACHE_COVERAGER
2209    php_info_print_table_row(2, "Coverage Dumper", XG(coveragedumper) && xc_coveragedump_dir && xc_coveragedump_dir[0] ? "enabled" : "disabled");
2210#endif
[1]2211    php_info_print_table_end();
[82]2212
[1]2213    DISPLAY_INI_ENTRIES();
2214}
2215/* }}} */
2216/* {{{ extension startup */
2217static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
2218{
2219    zend_extension extension;
2220
2221    extension = *new_extension;
2222    extension.handle = handle;
2223
2224    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
2225
2226    zend_llist_add_element(&zend_extensions, &extension);
2227#ifdef DEBUG
2228    fprintf(stderr, "registered\n");
2229#endif
2230}
2231
2232/* dirty check */
2233#if defined(COMPILE_DL_XCACHE) && (defined(ZEND_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__))
2234#   define zend_append_version_info(x) do { } while (0)
2235#else
2236extern void zend_append_version_info(zend_extension *extension);
2237#endif
2238static int xc_zend_extension_startup(zend_extension *extension)
2239{
2240    if (extension->startup) {
2241        if (extension->startup(extension) != SUCCESS) {
2242            return FAILURE;
2243        }
2244        zend_append_version_info(extension);
2245    }
2246    return SUCCESS;
2247}
2248/* }}} */
[82]2249static int xc_config_hash(xc_hash_t *p, char *name, char *default_value) /* {{{ */
2250{
2251    int bits, size;
2252    char *value;
2253
2254    if (cfg_get_string(name, &value) != SUCCESS) {
2255        value = default_value;
2256    }
2257
2258    p->size = zend_atoi(value, strlen(value));
2259    for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
2260        /* empty body */
2261    }
2262    p->size = size;
2263    p->bits = bits;
2264    p->mask = size - 1;
2265
2266    return SUCCESS;
2267}
2268/* }}} */
[90]2269static int xc_config_long(zend_ulong *p, char *name, char *default_value) /* {{{ */
[82]2270{
2271    char *value;
2272
2273    if (cfg_get_string(name, &value) != SUCCESS) {
2274        value = default_value;
2275    }
2276
2277    *p = zend_atoi(value, strlen(value));
2278    return SUCCESS;
2279}
2280/* }}} */
[1]2281/* {{{ PHP_MINIT_FUNCTION(xcache) */
2282static PHP_MINIT_FUNCTION(xcache)
2283{
2284    char *env;
[189]2285    zend_extension *ext;
2286    zend_llist_position lpos;
[1]2287
2288    xc_module_gotup = 1;
2289    if (!xc_zend_extension_gotup) {
2290        if (zend_get_extension(XCACHE_NAME) == NULL) {
2291            xc_zend_extension_register(&zend_extension_entry, 0);
2292            xc_zend_extension_startup(&zend_extension_entry);
2293        }
2294    }
2295
[189]2296    /* cache if there's an op_array_ctor */
2297    for (ext = zend_llist_get_first_ex(&zend_extensions, &lpos);
2298            ext;
2299            ext = zend_llist_get_next_ex(&zend_extensions, &lpos)) {
2300        if (ext->op_array_ctor) {
2301            xc_have_op_array_ctor = 1;
2302            break;
2303        }
2304    }
2305
2306
[92]2307#ifndef PHP_GINIT
[17]2308    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
[92]2309#endif
[17]2310    REGISTER_INI_ENTRIES();
2311
[1]2312    if (strcmp(sapi_module.name, "cli") == 0) {
2313        if ((env = getenv("XCACHE_TEST")) != NULL) {
2314            zend_alter_ini_entry("xcache.test", sizeof("xcache.test"), env, strlen(env) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP);
2315        }
2316        if (!xc_test) {
2317            /* disable cache for cli except for test */
2318            xc_php_size = xc_var_size = 0;
2319        }
2320    }
2321
[114]2322    xc_config_long(&xc_php_size,       "xcache.size",        "0");
2323    xc_config_hash(&xc_php_hcache,     "xcache.count",       "1");
2324    xc_config_hash(&xc_php_hentry,     "xcache.slots",      "8K");
[82]2325
[164]2326    xc_config_long(&xc_var_size,       "xcache.var_size",    "0");
2327    xc_config_hash(&xc_var_hcache,     "xcache.var_count",   "1");
2328    xc_config_hash(&xc_var_hentry,     "xcache.var_slots",  "8K");
[82]2329
[1]2330    if (xc_php_size <= 0) {
2331        xc_php_size = xc_php_hcache.size = 0;
2332    }
2333    if (xc_var_size <= 0) {
2334        xc_var_size = xc_var_hcache.size = 0;
2335    }
2336
[65]2337    if (xc_coredump_dir && xc_coredump_dir[0]) {
[75]2338        xcache_init_signal_handler();
[65]2339    }
[1]2340
2341    xc_init_constant(module_number TSRMLS_CC);
[148]2342    xc_shm_init_modules();
[1]2343
2344    if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
2345        if (!xc_init(module_number TSRMLS_CC)) {
[21]2346            zend_error(E_ERROR, "XCache: Cannot init");
[1]2347            goto err_init;
2348        }
2349        xc_initized = 1;
2350    }
2351
[27]2352#ifdef HAVE_XCACHE_COVERAGER
2353    xc_coverager_init(module_number TSRMLS_CC);
[1]2354#endif
2355
2356    return SUCCESS;
2357
2358err_init:
2359    return FAILURE;
2360}
2361/* }}} */
2362/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
2363static PHP_MSHUTDOWN_FUNCTION(xcache)
2364{
2365    if (xc_initized) {
2366        xc_destroy();
2367        xc_initized = 0;
2368    }
2369    if (xc_mmap_path) {
2370        pefree(xc_mmap_path, 1);
2371        xc_mmap_path = NULL;
2372    }
[148]2373    if (xc_shm_scheme) {
2374        pefree(xc_shm_scheme, 1);
2375        xc_shm_scheme = NULL;
2376    }
[1]2377
[27]2378#ifdef HAVE_XCACHE_COVERAGER
2379    xc_coverager_destroy();
[1]2380#endif
2381
[65]2382    if (xc_coredump_dir && xc_coredump_dir[0]) {
[75]2383        xcache_restore_signal_handler();
[65]2384    }
[1]2385    if (xc_coredump_dir) {
2386        pefree(xc_coredump_dir, 1);
2387        xc_coredump_dir = NULL;
2388    }
[92]2389#ifndef PHP_GINIT
2390#   ifdef ZTS
[25]2391    ts_free_id(xcache_globals_id);
[92]2392#   else
[1]2393    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
[92]2394#   endif
[1]2395#endif
2396
2397    UNREGISTER_INI_ENTRIES();
2398    return SUCCESS;
2399}
2400/* }}} */
2401/* {{{ PHP_RINIT_FUNCTION(xcache) */
2402static PHP_RINIT_FUNCTION(xcache)
2403{
2404    xc_request_init(TSRMLS_C);
2405    return SUCCESS;
2406}
2407/* }}} */
2408/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
2409#ifndef ZEND_ENGINE_2
2410static PHP_RSHUTDOWN_FUNCTION(xcache)
2411#else
2412static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
2413#endif
2414{
[18]2415#ifdef ZEND_ENGINE_2
[11]2416    TSRMLS_FETCH();
[18]2417#endif
[11]2418
[1]2419    xc_request_shutdown(TSRMLS_C);
2420    return SUCCESS;
2421}
2422/* }}} */
2423/* {{{ module definition structure */
2424
2425zend_module_entry xcache_module_entry = {
2426    STANDARD_MODULE_HEADER,
[21]2427    "XCache",
[1]2428    xcache_functions,
2429    PHP_MINIT(xcache),
2430    PHP_MSHUTDOWN(xcache),
2431    PHP_RINIT(xcache),
2432#ifndef ZEND_ENGINE_2
2433    PHP_RSHUTDOWN(xcache),
2434#else
2435    NULL,
2436#endif
2437    PHP_MINFO(xcache),
2438    XCACHE_VERSION,
[92]2439#ifdef PHP_GINIT
2440    PHP_MODULE_GLOBALS(xcache),
2441    PHP_GINIT(xcache),
2442    PHP_GSHUTDOWN(xcache),
2443#endif
[1]2444#ifdef ZEND_ENGINE_2
2445    ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
2446#else
2447    NULL,
2448    NULL,
2449#endif
2450    STANDARD_MODULE_PROPERTIES_EX
2451};
2452
2453#ifdef COMPILE_DL_XCACHE
2454ZEND_GET_MODULE(xcache)
2455#endif
2456/* }}} */
2457ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
2458{
2459    if (xc_zend_extension_gotup) {
2460        return FAILURE;
2461    }
2462    xc_zend_extension_gotup = 1;
2463    if (!xc_module_gotup) {
2464        return zend_startup_module(&xcache_module_entry);
2465    }
2466    return SUCCESS;
2467}
2468/* }}} */
2469ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
2470{
2471    /* empty */
2472}
2473/* }}} */
2474ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
2475{
[27]2476#ifdef HAVE_XCACHE_COVERAGER
2477    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
[1]2478#endif
2479}
2480/* }}} */
2481ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
2482{
2483#if 0
[27]2484    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
[1]2485#endif
2486}
2487/* }}} */
2488ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
2489{
2490#if 0
[27]2491    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
[1]2492#endif
2493}
2494/* }}} */
2495/* {{{ zend extension definition structure */
2496ZEND_DLEXPORT zend_extension zend_extension_entry = {
2497    XCACHE_NAME,
2498    XCACHE_VERSION,
2499    XCACHE_AUTHOR,
2500    XCACHE_URL,
2501    XCACHE_COPYRIGHT,
2502    xcache_zend_startup,
2503    xcache_zend_shutdown,
2504    NULL,           /* activate_func_t */
2505    NULL,           /* deactivate_func_t */
2506    NULL,           /* message_handler_func_t */
2507    NULL,           /* op_array_handler_func_t */
2508    xcache_statement_handler,
2509    xcache_fcall_begin_handler,
2510    xcache_fcall_end_handler,
2511    NULL,           /* op_array_ctor_func_t */
2512    NULL,           /* op_array_dtor_func_t */
2513    STANDARD_ZEND_EXTENSION_PROPERTIES
2514};
2515
2516#ifndef ZEND_EXT_API
2517#   define ZEND_EXT_API ZEND_DLEXPORT
2518#endif
2519#if COMPILE_DL_XCACHE
2520ZEND_EXTENSION();
2521#endif
2522/* }}} */
Note: See TracBrowser for help on using the repository browser.