source: trunk/xcache.c @ 205

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

avoid undef'ing DEBUG so one can put DEBUG into CFLAGS

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