source: trunk/xcache.c @ 75

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

proc all signal that may generate a core

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