source: branches/1.0/xcache.c @ 81

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

improved phpinfo displaying for those ini not in standard form.

File size: 52.5 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;
[1]405                for (p = *last; p; p = p->next) {
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
671#ifdef HAVE_XCACHE_OPTIMIZER
672    if (XG(optimizer)) {
673        xc_optimize(op_array TSRMLS_CC);
674    }
675#endif
676
677    php.op_array      = op_array;
678
679    php.funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
680    php.classinfo_cnt = zend_hash_num_elements(CG(class_table));
681
682    php.funcinfos     = ECALLOC_N(php.funcinfos, php.funcinfo_cnt);
683    if (!php.funcinfos) {
684        goto err_func;
685    }
686    php.classinfos    = ECALLOC_N(php.classinfos, php.classinfo_cnt);
687    if (!php.classinfos) {
688        goto err_class;
689    }
690    /* }}} */
691    /* {{{ shallow copy, pointers only */ {
692        Bucket *b;
693        unsigned int i;
694
695        b = CG(function_table)->pListHead;
696        for (i = 0; b; i ++, b = b->pListNext) {
697            xc_funcinfo_t *fi = &php.funcinfos[i];
698
699            assert(i < php.funcinfo_cnt);
700            assert(b->pData);
701            memcpy(&fi->func, b->pData, sizeof(zend_function));
[19]702            UNISW(NOTHING, fi->type = b->key.type;)
[1]703            fi->key        = BUCKET_KEY(b);
704            fi->key_size   = b->nKeyLength;
705        }
706
707        b = CG(class_table)->pListHead;
708        for (i = 0; b; i ++, b = b->pListNext) {
709            xc_classinfo_t *ci = &php.classinfos[i];
710
711            assert(i < php.classinfo_cnt);
712            assert(b->pData);
713            memcpy(&ci->cest, b->pData, sizeof(xc_cest_t));
[19]714            UNISW(NOTHING, ci->type = b->key.type;)
[1]715            ci->key        = BUCKET_KEY(b);
716            ci->key_size   = b->nKeyLength;
717            /* need to fix inside store */
718        }
719    }
720    /* }}} */
721    xc_entry_gc(TSRMLS_C);
722    ENTER_LOCK(cache) { /* {{{ store/add entry */
723        stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
724    } LEAVE_LOCK(cache);
725    /* }}} */
726#ifdef DEBUG
727    fprintf(stderr, "stored\n");
728#endif
729
730    efree(xce.data.php->classinfos);
731err_class:
732    efree(xce.data.php->funcinfos);
733err_func:
734err_oparray:
735err_bailout:
736
737    if (xc_test && stored_xce) {
738        /* no install, keep open_files too for h */
739        xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
740        sandbox.tmp_open_files->dtor = NULL;
741    }
742    else {
743        xc_sandbox_free(&sandbox, 1 TSRMLS_CC);
744    }
745
746    ENTER_LOCK(cache) {
747        cache->compiling = 0;
748    } LEAVE_LOCK(cache);
749    if (catched) {
750        zend_bailout();
751    }
752    if (xc_test && stored_xce) {
753        goto restore;
754    }
755    return op_array;
756
757restore:
758#ifdef DEBUG
759    fprintf(stderr, "restoring\n");
760#endif
761    xc_processor_restore_xc_entry_t(&xce, stored_xce, xc_readonly_protection TSRMLS_CC);
762    op_array = xc_entry_install(&xce, h TSRMLS_CC);
763
764    efree(xce.data.php->funcinfos);
765    efree(xce.data.php->classinfos);
766    efree(xce.data.php);
767#ifdef DEBUG
768    fprintf(stderr, "restored\n");
769#endif
770    return op_array;
771}
772/* }}} */
773
774/* gdb helper functions, but N/A for coredump */
775int xc_is_rw(const void *p) /* {{{ */
776{
777    int i;
778    if (!xc_initized) {
779        return 0;
780    }
781    for (i = 0; i < xc_php_hcache.size; i ++) {
782        if (xc_shm_is_readwrite(xc_php_caches[i]->shm, p)) {
783            return 1;
784        }
785    }
786    for (i = 0; i < xc_var_hcache.size; i ++) {
787        if (xc_shm_is_readwrite(xc_var_caches[i]->shm, p)) {
788            return 1;
789        }
790    }
791    return 0;
792}
793/* }}} */
794int xc_is_ro(const void *p) /* {{{ */
795{
796    int i;
797    if (!xc_initized) {
798        return 0;
799    }
800    for (i = 0; i < xc_php_hcache.size; i ++) {
801        if (xc_shm_is_readonly(xc_php_caches[i]->shm, p)) {
802            return 1;
803        }
804    }
805    for (i = 0; i < xc_var_hcache.size; i ++) {
806        if (xc_shm_is_readonly(xc_var_caches[i]->shm, p)) {
807            return 1;
808        }
809    }
810    return 0;
811}
812/* }}} */
813int xc_is_shm(const void *p) /* {{{ */
814{
815    return xc_is_ro(p) || xc_is_rw(p);
816}
817/* }}} */
818
819/* module helper function */
820static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
821{
[11]822    typedef struct {
[1]823        const char *prefix;
[20]824        zend_uchar (*getsize)();
[1]825        const char *(*get)(zend_uchar i);
[11]826    } xc_meminfo_t;
827    xc_meminfo_t nameinfos[] = {
[1]828        { "",        xc_get_op_type_count,   xc_get_op_type   },
829        { "",        xc_get_data_type_count, xc_get_data_type },
830        { "",        xc_get_opcode_count,    xc_get_opcode    },
831        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
832        { NULL, NULL, NULL }
833    };
[11]834    xc_meminfo_t* p;
[20]835    zend_uchar i, count;
[1]836    char const_name[96];
837    int const_name_len;
838    int undefdone = 0;
839
840    for (p = nameinfos; p->getsize; p ++) {
[20]841        count = p->getsize();
842        for (i = 0; i < count; i ++) {
[1]843            const char *name = p->get(i);
844            if (!name) continue;
845            if (strcmp(name, "UNDEF") == 0) {
846                if (undefdone) continue;
847                undefdone = 1;
848            }
849            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
850            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
851        }
852    }
853
854    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
855    zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
856    zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
857    return 0;
858}
859/* }}} */
[11]860static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
[1]861{
862    int i;
863    xc_cache_t *cache;
864    xc_shm_t *shm;
865
866    if (!caches) {
867        return NULL;
868    }
869    shm = NULL;
870    for (i = 0; i < hcache->size; i ++) {
871        cache = caches[i];
872        if (cache) {
873            if (cache->lck) {
874                xc_lock_destroy(cache->lck);
875            }
876            /* do NOT free
877            if (cache->entries) {
878                xc_mem_free(cache->mem, cache->entries);
879            }
880            xc_mem_free(cache->mem, cache);
881            */
882            xc_mem_destroy(cache->mem);
883            shm = cache->shm;
884        }
885    }
886    free(caches);
887    return shm;
888}
889/* }}} */
[11]890static 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]891{
892    xc_cache_t **caches = NULL, *cache;
893    xc_mem_t *mem;
894    int i;
[49]895    xc_memsize_t memsize;
[11]896
[49]897    memsize = shmsize / hcache->size;
[1]898
[49]899    /* Don't let it break out of mem after ALIGNed
900     * This is important for
901     * Simply loop until it fit our need
902     */
903    while (ALIGN(memsize) * hcache->size > shmsize && ALIGN(memsize) != memsize) {
904        if (memsize < ALIGN(1)) {
905            CHECK(NULL, "cache too small");
906        }
907        memsize --;
908    }
909
[1]910    CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
911
912    for (i = 0; i < hcache->size; i ++) {
[49]913        CHECK(mem            = xc_mem_init(ptr, memsize), "Failed init memory allocator");
914        ptr += memsize;
[1]915        CHECK(cache          = xc_mem_calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
916        CHECK(cache->entries = xc_mem_calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
917        CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
918
919        cache->hcache  = hcache;
920        cache->hentry  = hentry;
921        cache->shm     = shm;
922        cache->mem     = mem;
923        cache->cacheid = i;
924        caches[i] = cache;
925    }
926    assert(ptr <= (char*)xc_shm_ptr(shm) + shmsize);
927    return caches;
928
929err:
930    if (caches) {
931        xc_cache_destroy(caches, hcache);
932    }
933    return NULL;
934}
935/* }}} */
936static void xc_destroy() /* {{{ */
937{
938    xc_shm_t *shm = NULL;
939
940    if (origin_compile_file) {
941        zend_compile_file = origin_compile_file;
942        origin_compile_file = NULL;
943    }
944
945    if (xc_php_caches) {
946        shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
947        xc_php_caches = NULL;
948    }
949    if (xc_var_caches) {
950        shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
951        xc_var_caches = NULL;
952    }
953    if (shm) {
954        xc_shm_destroy(shm);
955    }
956}
957/* }}} */
958static int xc_init(int module_number TSRMLS_DC) /* {{{ */
959{
960    xc_shm_t *shm;
961    char *ptr;
962
[11]963    xc_php_caches = xc_var_caches = NULL;
964
[1]965    if (xc_php_size || xc_var_size) {
966        CHECK(shm = xc_shm_init(xc_mmap_path, ALIGN(xc_php_size) + ALIGN(xc_var_size), xc_readonly_protection), "Cannot create shm");
967        if (!xc_shm_can_readonly(shm)) {
968            xc_readonly_protection = 0;
969        }
970
971        ptr = (char *)xc_shm_ptr(shm);
972        if (xc_php_size) {
973            origin_compile_file = zend_compile_file;
974            zend_compile_file = xc_compile_file;
975
976            CHECK(xc_php_caches = xc_cache_init(shm, ptr, &xc_php_hcache, &xc_php_hentry, xc_php_size), "failed init opcode cache");
977            ptr += ALIGN(xc_php_size);
978        }
979
980        if (xc_var_size) {
981            CHECK(xc_var_caches = xc_cache_init(shm, ptr, &xc_var_hcache, &xc_var_hentry, xc_var_size), "failed init variable cache");
982        }
983    }
984    return 1;
985
986err:
987    if (xc_php_caches || xc_var_caches) {
988        xc_destroy();
989        /* shm destroied */
990    }
991    else if (shm) {
992        xc_shm_destroy(shm);
993    }
994    return 0;
995}
996/* }}} */
997static void xc_request_init(TSRMLS_D) /* {{{ */
998{
[17]999    int i;
1000
1001    if (xc_php_hcache.size && !XG(php_holds)) {
1002        XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
1003        for (i = 0; i < xc_php_hcache.size; i ++) {
1004            xc_stack_init(&XG(php_holds[i]));
1005        }
1006    }
1007
1008    if (xc_var_hcache.size && !XG(var_holds)) {
1009        XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
1010        for (i = 0; i < xc_var_hcache.size; i ++) {
1011            xc_stack_init(&XG(var_holds[i]));
1012        }
1013    }
1014
[1]1015    if (XG(cacher)) {
1016#if PHP_API_VERSION <= 20041225
1017        XG(request_time) = time(NULL);
1018#else
1019        XG(request_time) = sapi_get_request_time(TSRMLS_C);
1020#endif
1021    }
[27]1022#ifdef HAVE_XCACHE_COVERAGER
1023    xc_coverager_request_init(TSRMLS_C);
[1]1024#endif
1025}
1026/* }}} */
1027static void xc_request_shutdown(TSRMLS_D) /* {{{ */
1028{
1029    xc_entry_unholds(TSRMLS_C);
[27]1030#ifdef HAVE_XCACHE_COVERAGER
1031    xc_coverager_request_shutdown(TSRMLS_C);
[1]1032#endif
1033}
1034/* }}} */
1035static void xc_init_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
1036{
[17]1037    memset(xc_globals, 0, sizeof(zend_xcache_globals));
[1]1038}
1039/* }}} */
1040static void xc_shutdown_globals(zend_xcache_globals* xc_globals TSRMLS_DC) /* {{{ */
1041{
1042    int i;
1043
1044    if (xc_globals->php_holds != NULL) {
1045        for (i = 0; i < xc_php_hcache.size; i ++) {
1046            xc_stack_destroy(&xc_globals->php_holds[i]);
1047        }
1048        free(xc_globals->php_holds);
1049        xc_globals->php_holds = NULL;
1050    }
1051
1052    if (xc_globals->var_holds != NULL) {
1053        for (i = 0; i < xc_var_hcache.size; i ++) {
1054            xc_stack_destroy(&xc_globals->var_holds[i]);
1055        }
1056        free(xc_globals->var_holds);
1057        xc_globals->var_holds = NULL;
1058    }
1059}
1060/* }}} */
1061
1062/* user functions */
[55]1063static int xcache_admin_auth_check(TSRMLS_D) /* {{{ */
[34]1064{
1065    zval **server = NULL;
1066    zval **user = NULL;
1067    zval **pass = NULL;
1068    char *admin_user = NULL;
1069    char *admin_pass = NULL;
1070    HashTable *ht;
1071
1072    if (cfg_get_string("xcache.admin.user", &admin_user) == FAILURE || !admin_user[0]) {
1073        admin_user = NULL;
1074    }
1075    if (cfg_get_string("xcache.admin.pass", &admin_pass) == FAILURE || !admin_pass[0]) {
1076        admin_pass = NULL;
1077    }
1078
1079    if (admin_user == NULL || admin_pass == NULL) {
1080        php_error_docref(NULL TSRMLS_CC, E_ERROR, "xcache.admin.user and xcache.admin.pass is required");
1081        zend_bailout();
1082    }
1083    if (strlen(admin_pass) != 32) {
1084        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));
1085        zend_bailout();
1086    }
1087
1088    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != SUCCESS || Z_TYPE_PP(server) != IS_ARRAY) {
1089        php_error_docref(NULL TSRMLS_CC, E_ERROR, "_SERVER is corrupted");
1090        zend_bailout();
1091    }
1092    ht = HASH_OF((*server));
1093
1094    if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
1095        user = NULL;
1096    }
1097    else if (Z_TYPE_PP(user) != IS_STRING) {
1098        user = NULL;
1099    }
1100
1101    if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {
1102        pass = NULL;
1103    }
1104    else if (Z_TYPE_PP(pass) != IS_STRING) {
1105        pass = NULL;
1106    }
1107
1108    if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {
1109        PHP_MD5_CTX context;
1110        char md5str[33];
1111        unsigned char digest[16];
1112
1113        PHP_MD5Init(&context);
1114        PHP_MD5Update(&context, Z_STRVAL_PP(pass), Z_STRLEN_PP(pass));
1115        PHP_MD5Final(digest, &context);
1116
1117        md5str[0] = '\0';
1118        make_digest(md5str, digest);
1119        if (strcmp(admin_pass, md5str) == 0) {
1120            return 1;
1121        }
1122    }
1123
1124#define STR "WWW-authenticate: basic realm='XCache Administration'"
1125    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1126#undef STR
1127#define STR "HTTP/1.0 401 Unauthorized"
1128    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1129#undef STR
1130    ZEND_PUTS("XCache Auth Failed. User and Password is case sense\n");
1131
1132    zend_bailout();
1133    return 0;
1134}
1135/* }}} */
1136/* {{{ xcache_admin_operate */
[1]1137typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
[34]1138static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
[1]1139{
1140    long type;
1141    int size;
1142    xc_cache_t **caches, *cache;
1143    long id = 0;
1144
[11]1145    if (!xc_initized) {
1146        php_error_docref(NULL TSRMLS_CC, E_WARNING, "XCache is not initized");
1147        RETURN_FALSE;
1148    }
1149
[34]1150    xcache_admin_auth_check(TSRMLS_C);
1151
[1]1152    if (optype == XC_OP_COUNT) {
1153        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
1154            return;
1155        }
1156    }
1157    else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
1158        return;
1159    }
1160
1161    switch (type) {
1162        case XC_TYPE_PHP:
1163            size = xc_php_hcache.size;
1164            caches = xc_php_caches;
1165            break;
1166
1167        case XC_TYPE_VAR:
1168            size = xc_var_hcache.size;
1169            caches = xc_var_caches;
1170            break;
1171
1172        default:
1173            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
1174            RETURN_FALSE;
1175    }
1176
1177    switch (optype) {
1178        case XC_OP_COUNT:
1179            RETURN_LONG(size)
1180            break;
1181
1182        case XC_OP_INFO:
1183        case XC_OP_LIST:
1184            if (id < 0 || id >= size) {
1185                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1186                RETURN_FALSE;
1187            }
1188
1189            array_init(return_value);
1190
1191            cache = caches[id];
1192            ENTER_LOCK(cache) {
1193                if (optype == XC_OP_INFO) {
1194                    xc_fillinfo_dmz(cache, return_value TSRMLS_CC);
1195                }
1196                else {
1197                    xc_filllist_dmz(cache, return_value TSRMLS_CC);
1198                }
1199            } LEAVE_LOCK(cache);
1200            break;
1201        case XC_OP_CLEAR:
1202            {
1203                xc_entry_t *e;
1204                int i, c;
1205
1206                if (id < 0 || id >= size) {
1207                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
1208                    RETURN_FALSE;
1209                }
1210
1211                cache = caches[id];
1212                ENTER_LOCK(cache) {
1213                    for (i = 0, c = cache->hentry->size; i < c; i ++) {
1214                        for (e = cache->entries[i]; e; e = e->next) {
1215                            xc_entry_remove_dmz(e TSRMLS_CC);
1216                        }
1217                        cache->entries[i] = NULL;
1218                    }
1219                } LEAVE_LOCK(cache);
1220                xc_entry_gc(TSRMLS_C);
1221            }
1222            break;
1223
1224        default:
1225            assert(0);
1226    }
1227}
1228/* }}} */
[9]1229/* {{{ proto int xcache_count(int type)
1230   Return count of cache on specified cache type */
[1]1231PHP_FUNCTION(xcache_count)
1232{
[34]1233    xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1234}
1235/* }}} */
[9]1236/* {{{ proto array xcache_info(int type, int id)
1237   Get cache info by id on specified cache type */
[1]1238PHP_FUNCTION(xcache_info)
1239{
[34]1240    xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1241}
1242/* }}} */
[9]1243/* {{{ proto array xcache_list(int type, int id)
1244   Get cache entries list by id on specified cache type */
[1]1245PHP_FUNCTION(xcache_list)
1246{
[34]1247    xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1248}
1249/* }}} */
[9]1250/* {{{ proto array xcache_clear_cache(int type, int id)
1251   Clear cache by id on specified cache type */
[1]1252PHP_FUNCTION(xcache_clear_cache)
1253{
[34]1254    xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
[1]1255}
1256/* }}} */
1257
1258static int xc_entry_init_key_var(xc_entry_t *xce, zval *name TSRMLS_DC) /* {{{ */
1259{
1260    xc_hash_value_t hv;
1261    int cacheid;
1262
1263    switch (Z_TYPE_P(name)) {
1264#ifdef IS_UNICODE
1265        case IS_UNICODE:
1266#endif
1267        case IS_STRING:
1268            break;
1269        default:
1270#ifdef IS_UNICODE
1271            convert_to_text(name);
1272#else
1273            convert_to_string(name);
1274#endif
1275    }
1276#ifdef IS_UNICODE
1277    xce->name_type = name->type;
1278#endif
1279    xce->name = name->value;
1280
1281    hv = xc_entry_hash_var(xce);
1282
1283    cacheid = (hv & xc_var_hcache.mask);
1284    xce->cache = xc_var_caches[cacheid];
1285    hv >>= xc_var_hcache.bits;
1286    xce->hvalue = (hv & xc_var_hentry.mask);
1287
1288    xce->type = XC_TYPE_VAR;
1289    return SUCCESS;
1290}
1291/* }}} */
1292#define TIME_MAX (sizeof(time_t) == sizeof(long) ? LONG_MAX : INT_MAX)
[9]1293/* {{{ proto mixed xcache_get(string name)
1294   Get cached data by specified name */
[1]1295PHP_FUNCTION(xcache_get)
1296{
1297    xc_entry_t xce, *stored_xce;
1298    xc_entry_data_var_t var;
1299    zval *name;
1300
1301    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1302        return;
1303    }
1304    xce.data.var = &var;
1305    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1306
1307    ENTER_LOCK(xce.cache) {
1308        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1309        if (stored_xce) {
1310            if (XG(request_time) <= stored_xce->data.var->etime) {
1311                xc_processor_restore_zval(return_value, stored_xce->data.var->value TSRMLS_CC);
1312                /* return */
1313                break;
1314            }
1315            else {
[11]1316                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1317            }
1318        }
1319
1320        RETVAL_NULL();
1321    } LEAVE_LOCK(xce.cache);
1322}
1323/* }}} */
[9]1324/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
1325   Store data to cache by specified name */
[1]1326PHP_FUNCTION(xcache_set)
1327{
1328    xc_entry_t xce, *stored_xce;
1329    xc_entry_data_var_t var;
1330    zval *name;
1331    zval *value;
1332    long ttl = 0;
1333
1334    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &ttl) == FAILURE) {
1335        return;
1336    }
1337    xce.data.var = &var;
1338    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1339
1340    ENTER_LOCK(xce.cache) {
1341        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1342        if (stored_xce) {
[11]1343            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1344        }
1345        var.value = value;
1346        var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
[11]1347        RETVAL_BOOL(xc_entry_store_dmz(&xce TSRMLS_CC) != NULL ? 1 : 0);
[1]1348    } LEAVE_LOCK(xce.cache);
1349}
1350/* }}} */
[9]1351/* {{{ proto bool  xcache_isset(string name)
1352   Check if an entry exists in cache by specified name */
[1]1353PHP_FUNCTION(xcache_isset)
1354{
1355    xc_entry_t xce, *stored_xce;
1356    xc_entry_data_var_t var;
1357    zval *name;
1358
1359    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1360        return;
1361    }
1362    xce.data.var = &var;
1363    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1364
1365    ENTER_LOCK(xce.cache) {
1366        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1367        if (stored_xce) {
1368            if (XG(request_time) <= stored_xce->data.var->etime) {
1369                RETVAL_TRUE;
1370                /* return */
1371                break;
1372            }
1373            else {
[11]1374                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1375            }
1376        }
1377
1378        RETVAL_FALSE;
1379    } LEAVE_LOCK(xce.cache);
1380}
1381/* }}} */
[9]1382/* {{{ proto bool  xcache_unset(string name)
1383   Unset existing data in cache by specified name */
[1]1384PHP_FUNCTION(xcache_unset)
1385{
1386    xc_entry_t xce, *stored_xce;
1387    xc_entry_data_var_t var;
1388    zval *name;
1389
1390    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
1391        return;
1392    }
1393    xce.data.var = &var;
1394    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1395
1396    ENTER_LOCK(xce.cache) {
1397        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1398        if (stored_xce) {
[11]1399            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1400            RETVAL_TRUE;
1401        }
1402        else {
1403            RETVAL_FALSE;
1404        }
1405    } LEAVE_LOCK(xce.cache);
1406}
1407/* }}} */
1408static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
1409{
1410    xc_entry_t xce, *stored_xce;
1411    xc_entry_data_var_t var, *stored_var;
1412    zval *name;
1413    long count = 1;
1414    long ttl = 0;
1415    long value = 0;
1416    zval oldzval;
1417
1418    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &ttl) == FAILURE) {
1419        return;
1420    }
1421    xce.data.var = &var;
1422    xc_entry_init_key_var(&xce, name TSRMLS_CC);
1423
1424    ENTER_LOCK(xce.cache) {
1425        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1426        if (stored_xce) {
1427#ifdef DEBUG
1428            fprintf(stderr, "incdec: gotxce %s\n", xce.name.str.val);
1429#endif
1430            stored_var = stored_xce->data.var;
1431            /* timeout */
1432            if (XG(request_time) > stored_var->etime) {
1433#ifdef DEBUG
1434                fprintf(stderr, "incdec: expired\n");
1435#endif
[11]1436                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1437                stored_xce = NULL;
1438            }
1439            else {
1440                /* do it in place */
1441                if (Z_TYPE_P(stored_var->value) == IS_LONG) {
1442#ifdef DEBUG
1443                    fprintf(stderr, "incdec: islong\n");
1444#endif
1445                    value = Z_LVAL_P(stored_var->value);
1446                    value += (inc == 1 ? count : - count);
1447                    RETVAL_LONG(value);
1448                    Z_LVAL_P(stored_var->value) = value;
1449                    break;
1450                }
1451                else {
1452#ifdef DEBUG
1453                    fprintf(stderr, "incdec: notlong\n");
1454#endif
1455                    xc_processor_restore_zval(&oldzval, stored_xce->data.var->value TSRMLS_CC);
1456                    convert_to_long(&oldzval);
1457                    value = Z_LVAL(oldzval);
1458                    zval_dtor(&oldzval);
1459                }
1460            }
1461        }
1462#ifdef DEBUG
1463        else {
1464            fprintf(stderr, "incdec: %s not found\n", xce.name.str.val);
1465        }
1466#endif
1467
1468        value += (inc == 1 ? count : - count);
1469        RETVAL_LONG(value);
1470        var.value = return_value;
1471        var.etime = ttl ? XG(request_time) + ttl : TIME_MAX;
1472        if (stored_xce) {
1473            xce.atime = stored_xce->atime;
1474            xce.ctime = stored_xce->ctime;
1475            xce.hits  = stored_xce->hits;
[11]1476            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
[1]1477        }
[11]1478        xc_entry_store_dmz(&xce TSRMLS_CC);
[1]1479
1480    } LEAVE_LOCK(xce.cache);
1481}
1482/* }}} */
[9]1483/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
1484   Increase an int counter in cache by specified name, create it if not exists */
[1]1485PHP_FUNCTION(xcache_inc)
1486{
1487    xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1488}
1489/* }}} */
[9]1490/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
1491   Decrease an int counter in cache by specified name, create it if not exists */
[1]1492PHP_FUNCTION(xcache_dec)
1493{
1494    xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1495}
1496/* }}} */
[9]1497/* {{{ proto string xcache_asm(string filename)
1498 */
[1]1499#ifdef HAVE_XCACHE_ASSEMBLER
1500PHP_FUNCTION(xcache_asm)
1501{
1502}
1503#endif
1504/* }}} */
1505#ifdef HAVE_XCACHE_DISASSEMBLER
[9]1506/* {{{ proto array  xcache_dasm_file(string filename)
1507   Disassemble file into opcode array by filename */
[1]1508PHP_FUNCTION(xcache_dasm_file)
1509{
1510    char *filename;
1511    long filename_len;
1512
1513    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1514        return;
1515    }
1516    if (!filename_len) RETURN_FALSE;
1517
1518    xc_dasm_file(return_value, filename TSRMLS_CC);
1519}
1520/* }}} */
[9]1521/* {{{ proto array  xcache_dasm_string(string code)
1522   Disassemble php code into opcode array */
[1]1523PHP_FUNCTION(xcache_dasm_string)
1524{
1525    zval *code;
1526
1527    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
1528        return;
1529    }
1530    xc_dasm_string(return_value, code TSRMLS_CC);
1531}
1532/* }}} */
1533#endif
[9]1534/* {{{ proto string xcache_encode(string filename)
1535   Encode php file into XCache opcode encoded format */
[1]1536#ifdef HAVE_XCACHE_ENCODER
1537PHP_FUNCTION(xcache_encode)
1538{
1539}
1540#endif
1541/* }}} */
[9]1542/* {{{ proto bool xcache_decode_file(string filename)
1543   Decode(load) opcode from XCache encoded format file */
[1]1544#ifdef HAVE_XCACHE_DECODER
[9]1545PHP_FUNCTION(xcache_decode_file)
[1]1546{
1547}
1548#endif
1549/* }}} */
[9]1550/* {{{ proto bool xcache_decode_string(string data)
1551   Decode(load) opcode from XCache encoded format data */
1552#ifdef HAVE_XCACHE_DECODER
1553PHP_FUNCTION(xcache_decode_string)
1554{
1555}
1556#endif
1557/* }}} */
[1]1558/* {{{ xc_call_getter */
1559typedef const char *(xc_name_getter_t)(zend_uchar type);
1560static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
1561{
1562    long spec;
1563    const char *name;
1564
1565    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1566        return;
1567    }
1568    if (spec >= 0 && spec < count) {
[11]1569        name = getter((zend_uchar) spec);
[1]1570        if (name) {
1571            /* RETURN_STRING */
1572            int len = strlen(name);
1573            return_value->value.str.len = len;
1574            return_value->value.str.val = estrndup(name, len);
1575            return_value->type = IS_STRING; 
1576            return;
1577        }
1578    }
1579    RETURN_NULL();
1580}
1581/* }}} */
1582/* {{{ proto string xcache_get_op_type(int op_type) */
1583PHP_FUNCTION(xcache_get_op_type)
1584{
1585    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1586}
1587/* }}} */
1588/* {{{ proto string xcache_get_data_type(int type) */
1589PHP_FUNCTION(xcache_get_data_type)
1590{
1591    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1592}
1593/* }}} */
1594/* {{{ proto string xcache_get_opcode(int opcode) */
1595PHP_FUNCTION(xcache_get_opcode)
1596{
1597    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1598}
1599/* }}} */
1600/* {{{ proto string xcache_get_op_spec(int op_type) */
1601PHP_FUNCTION(xcache_get_op_spec)
1602{
1603    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
1604}
1605/* }}} */
[8]1606#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
[1]1607/* {{{ proto string xcache_get_opcode_spec(int opcode) */
1608PHP_FUNCTION(xcache_get_opcode_spec)
1609{
1610    long spec;
1611    const xc_opcode_spec_t *opspec;
1612
1613    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
1614        return;
1615    }
[17]1616    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
[11]1617        opspec = xc_get_opcode_spec((zend_uchar) spec);
[1]1618        if (opspec) {
1619            array_init(return_value);
1620            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
1621            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
1622            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
1623            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
1624            return;
1625        }
1626    }
1627    RETURN_NULL();
1628}
1629/* }}} */
[8]1630#endif
[1]1631/* {{{ proto mixed xcache_get_special_value(zval value) */
1632PHP_FUNCTION(xcache_get_special_value)
1633{
1634    zval *value;
1635
1636    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
1637        return;
1638    }
1639
1640    if (value->type == IS_CONSTANT) {
1641        *return_value = *value;
1642        zval_copy_ctor(return_value);
1643        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
1644        return;
1645    }
1646
1647    if (value->type == IS_CONSTANT_ARRAY) {
1648        *return_value = *value;
1649        zval_copy_ctor(return_value);
1650        return_value->type = IS_ARRAY;
1651        return;
1652    }
1653
1654    RETURN_NULL();
1655}
1656/* }}} */
1657/* {{{ proto string xcache_coredump(int op_type) */
1658PHP_FUNCTION(xcache_coredump)
1659{
[9]1660    if (xc_test) {
1661        raise(SIGSEGV);
1662    }
1663    else {
1664        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
1665    }
[1]1666}
1667/* }}} */
1668/* {{{ proto string xcache_is_autoglobal(string name) */
1669PHP_FUNCTION(xcache_is_autoglobal)
1670{
1671    char *name;
1672    long name_len;
1673
1674    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
1675        return;
1676    }
1677
1678    RETURN_BOOL(zend_hash_exists(CG(auto_globals), name, name_len + 1));
1679}
1680/* }}} */
1681static function_entry xcache_functions[] = /* {{{ */
1682{
1683    PHP_FE(xcache_count,             NULL)
1684    PHP_FE(xcache_info,              NULL)
1685    PHP_FE(xcache_list,              NULL)
1686    PHP_FE(xcache_clear_cache,       NULL)
1687    PHP_FE(xcache_coredump,          NULL)
1688#ifdef HAVE_XCACHE_ASSEMBLER
1689    PHP_FE(xcache_asm,               NULL)
1690#endif
1691#ifdef HAVE_XCACHE_DISASSEMBLER
1692    PHP_FE(xcache_dasm_file,         NULL)
1693    PHP_FE(xcache_dasm_string,       NULL)
1694#endif
1695#ifdef HAVE_XCACHE_ENCODER
1696    PHP_FE(xcache_encode,            NULL)
1697#endif
1698#ifdef HAVE_XCACHE_DECODER
[9]1699    PHP_FE(xcache_decode_file,       NULL)
1700    PHP_FE(xcache_decode_string,     NULL)
[1]1701#endif
[27]1702#ifdef HAVE_XCACHE_COVERAGER
1703    PHP_FE(xcache_coverager_decode,  NULL)
[1]1704#endif
1705    PHP_FE(xcache_get_special_value, NULL)
1706    PHP_FE(xcache_get_op_type,       NULL)
1707    PHP_FE(xcache_get_data_type,     NULL)
1708    PHP_FE(xcache_get_opcode,        NULL)
[8]1709#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
[1]1710    PHP_FE(xcache_get_opcode_spec,   NULL)
[8]1711#endif
[1]1712    PHP_FE(xcache_is_autoglobal,     NULL)
1713    PHP_FE(xcache_inc,               NULL)
1714    PHP_FE(xcache_dec,               NULL)
1715    PHP_FE(xcache_get,               NULL)
1716    PHP_FE(xcache_set,               NULL)
1717    PHP_FE(xcache_isset,             NULL)
1718    PHP_FE(xcache_unset,             NULL)
1719    {NULL, NULL,                     NULL}
1720};
1721/* }}} */
1722
1723/* signal handler */
1724static void (*original_sigsegv_handler)(int) = NULL;
[65]1725static void xcache_sigsegv_handler(int sig) /* {{{ */
[1]1726{
[65]1727    if (original_sigsegv_handler != xcache_sigsegv_handler) {
[1]1728        signal(SIGSEGV, original_sigsegv_handler);
[9]1729    }
1730    else {
[1]1731        signal(SIGSEGV, SIG_DFL);
1732    }
1733    if (xc_coredump_dir && xc_coredump_dir[0]) {
1734        chdir(xc_coredump_dir);
1735    }
[65]1736    raise(sig);
[1]1737}
1738/* }}} */
1739
1740/* {{{ PHP_INI */
1741
1742static PHP_INI_MH(xc_OnUpdateBool)
1743{
1744    zend_bool *p = (zend_bool *)mh_arg1;
1745
1746    if (strncasecmp("on", new_value, sizeof("on"))) {
1747        *p = (zend_bool) atoi(new_value);
1748    }
1749    else {
1750        *p = (zend_bool) 1;
1751    }
1752    return SUCCESS;
1753}
1754
1755static PHP_INI_MH(xc_OnUpdateString)
1756{
1757    char **p = (char**)mh_arg1;
1758    if (*p) {
1759        pefree(*p, 1);
1760    }
1761    *p = pemalloc(strlen(new_value) + 1, 1);
1762    strcpy(*p, new_value);
1763    return SUCCESS;
1764}
[74]1765
[1]1766#ifdef ZEND_ENGINE_2
1767#define OnUpdateInt OnUpdateLong
1768#endif
1769
[21]1770#ifdef ZEND_WIN32
1771#   define DEFAULT_PATH "xcache"
1772#else
1773#   define DEFAULT_PATH "/dev/zero"
1774#endif
[1]1775PHP_INI_BEGIN()
[21]1776    PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
[1]1777    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
1778    PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
1779    PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
1780
1781    STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
1782#ifdef HAVE_XCACHE_OPTIMIZER
1783    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
1784#endif
[27]1785#ifdef HAVE_XCACHE_COVERAGER
[39]1786    PHP_INI_ENTRY1     ("xcache.coveragedump_directory", "/tmp/pcov/", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coveragedump_dir)
1787    STD_PHP_INI_BOOLEAN("xcache.coveragedumper" ,                 "0", PHP_INI_ALL,    OnUpdateBool,        coveragedumper,    zend_xcache_globals, xcache_globals)
[1]1788#endif
1789PHP_INI_END()
1790/* }}} */
[81]1791static int xc_config_long_disp(char *name, char *default_value) /* {{{ */
1792{
1793    char *value;
1794    char buf[100];
1795
1796    if (cfg_get_string(name, &value) != SUCCESS) {
1797        sprintf(buf, "%s (default)", default_value);
1798        php_info_print_table_row(2, name, buf);
1799    }
1800    else {
1801        php_info_print_table_row(2, name, value);
1802    }
1803
1804    return SUCCESS;
1805}
1806/* }}} */
1807#define xc_config_hash_disp xc_config_long_disp
[1]1808/* {{{ PHP_MINFO_FUNCTION(xcache) */
1809static PHP_MINFO_FUNCTION(xcache)
1810{
[81]1811    char buf[100];
1812    char *ptr;
1813
[1]1814    php_info_print_table_start();
1815    php_info_print_table_header(2, "XCache Support", (xc_php_size || xc_var_size) ? "enabled" : "disabled");
1816    php_info_print_table_row(2, "Version", XCACHE_VERSION);
[26]1817    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
[81]1818    php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A or disabled");
1819
1820    if (xc_php_size) {
1821        ptr = _php_math_number_format(xc_php_size, 0, '.', ',');
1822        sprintf(buf, "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_php_hcache.size, xc_php_hentry.size);
1823        php_info_print_table_row(2, "Opcode Cache", buf);
1824        efree(ptr);
1825    }
1826    else {
1827        php_info_print_table_row(2, "Opcode Cache", "disabled");
1828    }
1829    if (xc_var_size) {
1830        ptr = _php_math_number_format(xc_var_size, 0, '.', ',');
1831        sprintf(buf, "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_var_hcache.size, xc_var_hentry.size);
1832        php_info_print_table_row(2, "Variable Cache", buf);
1833        efree(ptr);
1834    }
1835    else {
1836        php_info_print_table_row(2, "Variable Cache", "disabled");
1837    }
[26]1838#ifdef HAVE_XCACHE_COVERAGER
1839    php_info_print_table_row(2, "Coverage Dumper", XG(coveragedumper) && xc_coveragedump_dir && xc_coveragedump_dir[0] ? "enabled" : "disabled");
1840#endif
[1]1841    php_info_print_table_end();
[81]1842
1843    php_info_print_table_start();
1844    php_info_print_table_header(2, "Directive ", "Value");
1845    xc_config_long_disp("xcache.size",       "0");
1846    xc_config_hash_disp("xcache.count",      "1");
1847    xc_config_hash_disp("xcache.slots",     "8K");
1848
1849    xc_config_long_disp("xcache.var_size",   "0");
1850    xc_config_hash_disp("xcache.var_count",  "1");
1851    xc_config_hash_disp("xcache.var_slots", "8K");
1852    php_info_print_table_end();
1853
[1]1854    DISPLAY_INI_ENTRIES();
1855}
1856/* }}} */
1857/* {{{ extension startup */
1858static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
1859{
1860    zend_extension extension;
1861
1862    extension = *new_extension;
1863    extension.handle = handle;
1864
1865    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
1866
1867    zend_llist_add_element(&zend_extensions, &extension);
1868#ifdef DEBUG
1869    fprintf(stderr, "registered\n");
1870#endif
1871}
1872
1873/* dirty check */
1874#if defined(COMPILE_DL_XCACHE) && (defined(ZEND_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__))
1875#   define zend_append_version_info(x) do { } while (0)
1876#else
1877extern void zend_append_version_info(zend_extension *extension);
1878#endif
1879static int xc_zend_extension_startup(zend_extension *extension)
1880{
1881    if (extension->startup) {
1882        if (extension->startup(extension) != SUCCESS) {
1883            return FAILURE;
1884        }
1885        zend_append_version_info(extension);
1886    }
1887    return SUCCESS;
1888}
1889/* }}} */
[74]1890static int xc_config_hash(xc_hash_t *p, char *name, char *default_value) /* {{{ */
1891{
1892    int bits, size;
1893    char *value;
1894
1895    if (cfg_get_string(name, &value) != SUCCESS) {
1896        value = default_value;
1897    }
1898
1899    p->size = zend_atoi(value, strlen(value));
1900    for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
1901        /* empty body */
1902    }
1903    p->size = size;
1904    p->bits = bits;
1905    p->mask = size - 1;
1906
1907    return SUCCESS;
1908}
[81]1909/* }}} */
[74]1910static int xc_config_long(long *p, char *name, char *default_value) /* {{{ */
1911{
1912    char *value;
1913
1914    if (cfg_get_string(name, &value) != SUCCESS) {
1915        value = default_value;
1916    }
1917
1918    *p = zend_atoi(value, strlen(value));
1919    return SUCCESS;
1920}
1921/* }}} */
[1]1922/* {{{ PHP_MINIT_FUNCTION(xcache) */
1923static PHP_MINIT_FUNCTION(xcache)
1924{
1925    char *env;
1926
1927    xc_module_gotup = 1;
1928    if (!xc_zend_extension_gotup) {
1929        if (zend_get_extension(XCACHE_NAME) == NULL) {
1930            xc_zend_extension_register(&zend_extension_entry, 0);
1931            xc_zend_extension_startup(&zend_extension_entry);
1932        }
1933    }
1934
[17]1935    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
1936    REGISTER_INI_ENTRIES();
1937
[1]1938    if (strcmp(sapi_module.name, "cli") == 0) {
1939        if ((env = getenv("XCACHE_TEST")) != NULL) {
1940            zend_alter_ini_entry("xcache.test", sizeof("xcache.test"), env, strlen(env) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP);
1941        }
1942        if (!xc_test) {
1943            /* disable cache for cli except for test */
1944            xc_php_size = xc_var_size = 0;
1945        }
1946    }
1947
[74]1948    xc_config_long(&xc_php_size,   "xcache.size",       "0");
1949    xc_config_hash(&xc_php_hcache, "xcache.count",      "1");
1950    xc_config_hash(&xc_php_hentry, "xcache.slots",     "8K");
1951
1952    xc_config_long(&xc_var_size,   "xcache.var_size",   "0");
1953    xc_config_hash(&xc_var_hcache, "xcache.var_count",  "1");
1954    xc_config_hash(&xc_var_hentry, "xcache.var_slots", "8K");
1955
[1]1956    if (xc_php_size <= 0) {
1957        xc_php_size = xc_php_hcache.size = 0;
1958    }
1959    if (xc_var_size <= 0) {
1960        xc_var_size = xc_var_hcache.size = 0;
1961    }
1962
[65]1963    if (xc_coredump_dir && xc_coredump_dir[0]) {
1964        original_sigsegv_handler = signal(SIGSEGV, xcache_sigsegv_handler);
1965    }
[1]1966
1967    xc_init_constant(module_number TSRMLS_CC);
1968
1969    if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
1970        if (!xc_init(module_number TSRMLS_CC)) {
[21]1971            zend_error(E_ERROR, "XCache: Cannot init");
[1]1972            goto err_init;
1973        }
1974        xc_initized = 1;
1975    }
1976
[27]1977#ifdef HAVE_XCACHE_COVERAGER
1978    xc_coverager_init(module_number TSRMLS_CC);
[1]1979#endif
1980
1981    return SUCCESS;
1982
1983err_init:
1984    return FAILURE;
1985}
1986/* }}} */
1987/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
1988static PHP_MSHUTDOWN_FUNCTION(xcache)
1989{
1990    if (xc_initized) {
1991        xc_destroy();
1992        xc_initized = 0;
1993    }
1994    if (xc_mmap_path) {
1995        pefree(xc_mmap_path, 1);
1996        xc_mmap_path = NULL;
1997    }
1998
[27]1999#ifdef HAVE_XCACHE_COVERAGER
2000    xc_coverager_destroy();
[1]2001#endif
2002
[65]2003    if (xc_coredump_dir && xc_coredump_dir[0]) {
2004        signal(SIGSEGV, original_sigsegv_handler);
2005    }
[1]2006    if (xc_coredump_dir) {
2007        pefree(xc_coredump_dir, 1);
2008        xc_coredump_dir = NULL;
2009    }
[25]2010#ifdef ZTS
2011    ts_free_id(xcache_globals_id);
2012#else
[1]2013    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
2014#endif
2015
2016    UNREGISTER_INI_ENTRIES();
2017    return SUCCESS;
2018}
2019/* }}} */
2020/* {{{ PHP_RINIT_FUNCTION(xcache) */
2021static PHP_RINIT_FUNCTION(xcache)
2022{
2023    xc_request_init(TSRMLS_C);
2024    return SUCCESS;
2025}
2026/* }}} */
2027/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
2028#ifndef ZEND_ENGINE_2
2029static PHP_RSHUTDOWN_FUNCTION(xcache)
2030#else
2031static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
2032#endif
2033{
[18]2034#ifdef ZEND_ENGINE_2
[11]2035    TSRMLS_FETCH();
[18]2036#endif
[11]2037
[1]2038    xc_request_shutdown(TSRMLS_C);
2039    return SUCCESS;
2040}
2041/* }}} */
2042/* {{{ module definition structure */
2043
2044zend_module_entry xcache_module_entry = {
2045    STANDARD_MODULE_HEADER,
[21]2046    "XCache",
[1]2047    xcache_functions,
2048    PHP_MINIT(xcache),
2049    PHP_MSHUTDOWN(xcache),
2050    PHP_RINIT(xcache),
2051#ifndef ZEND_ENGINE_2
2052    PHP_RSHUTDOWN(xcache),
2053#else
2054    NULL,
2055#endif
2056    PHP_MINFO(xcache),
2057    XCACHE_VERSION,
2058#ifdef ZEND_ENGINE_2
2059    ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
2060#else
2061    NULL,
2062    NULL,
2063#endif
2064    STANDARD_MODULE_PROPERTIES_EX
2065};
2066
2067#ifdef COMPILE_DL_XCACHE
2068ZEND_GET_MODULE(xcache)
2069#endif
2070/* }}} */
2071ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
2072{
2073    if (xc_zend_extension_gotup) {
2074        return FAILURE;
2075    }
2076    xc_zend_extension_gotup = 1;
2077    if (!xc_module_gotup) {
2078        return zend_startup_module(&xcache_module_entry);
2079    }
2080    return SUCCESS;
2081}
2082/* }}} */
2083ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
2084{
2085    /* empty */
2086}
2087/* }}} */
2088ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
2089{
[27]2090#ifdef HAVE_XCACHE_COVERAGER
2091    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
[1]2092#endif
2093}
2094/* }}} */
2095ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
2096{
2097#if 0
[27]2098    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
[1]2099#endif
2100}
2101/* }}} */
2102ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
2103{
2104#if 0
[27]2105    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
[1]2106#endif
2107}
2108/* }}} */
2109/* {{{ zend extension definition structure */
2110ZEND_DLEXPORT zend_extension zend_extension_entry = {
2111    XCACHE_NAME,
2112    XCACHE_VERSION,
2113    XCACHE_AUTHOR,
2114    XCACHE_URL,
2115    XCACHE_COPYRIGHT,
2116    xcache_zend_startup,
2117    xcache_zend_shutdown,
2118    NULL,           /* activate_func_t */
2119    NULL,           /* deactivate_func_t */
2120    NULL,           /* message_handler_func_t */
2121    NULL,           /* op_array_handler_func_t */
2122    xcache_statement_handler,
2123    xcache_fcall_begin_handler,
2124    xcache_fcall_end_handler,
2125    NULL,           /* op_array_ctor_func_t */
2126    NULL,           /* op_array_dtor_func_t */
2127    STANDARD_ZEND_EXTENSION_PROPERTIES
2128};
2129
2130#ifndef ZEND_EXT_API
2131#   define ZEND_EXT_API ZEND_DLEXPORT
2132#endif
2133#if COMPILE_DL_XCACHE
2134ZEND_EXTENSION();
2135#endif
2136/* }}} */
Note: See TracBrowser for help on using the repository browser.