source: svn/branches/1.0/xcache.c @ 143

Last change on this file since 143 was 143, checked in by Xuefer, 10 years ago

fixed string parameter parsing arg type for disassembler functions. thanks to Nuno Lopes' check_parameters.php

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