source: trunk/xcache.c @ 522

Last change on this file since 522 was 522, checked in by moo, 6 years ago

slide hits per second and hour

  • Property svn:eol-style set to native
File size: 81.8 KB
Line 
1
2#if 0
3#define DEBUG
4#endif
5
6#if 0
7#define SHOW_DPRINT
8#endif
9
10/* {{{ macros */
11#include <stdlib.h>
12#include <stdio.h>
13#include <string.h>
14
15#include <signal.h>
16
17#include "php.h"
18#include "ext/standard/info.h"
19#include "ext/standard/md5.h"
20#include "ext/standard/php_math.h"
21#include "zend_extensions.h"
22#include "SAPI.h"
23
24#include "xcache.h"
25#include "optimizer.h"
26#include "coverager.h"
27#include "disassembler.h"
28#include "align.h"
29#include "stack.h"
30#include "xcache_globals.h"
31#include "processor.h"
32#include "const_string.h"
33#include "opcode_spec.h"
34#include "utils.h"
35
36#define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > pentry->ctime + (pentry)->ttl)
37#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
38#define LOCK(x) xc_lock(x->lck)
39#define UNLOCK(x) xc_unlock(x->lck)
40
41#define ENTER_LOCK_EX(x) \
42    xc_lock(x->lck); \
43    zend_try { \
44        do
45#define LEAVE_LOCK_EX(x) \
46        while (0); \
47    } zend_catch { \
48        catched = 1; \
49    } zend_end_try(); \
50    xc_unlock(x->lck)
51
52#define ENTER_LOCK(x) do { \
53    int catched = 0; \
54    ENTER_LOCK_EX(x)
55#define LEAVE_LOCK(x) \
56    LEAVE_LOCK_EX(x); \
57    if (catched) { \
58        zend_bailout(); \
59    } \
60} while(0)
61
62/* }}} */
63
64/* {{{ globals */
65static char *xc_shm_scheme = NULL;
66static char *xc_mmap_path = NULL;
67static char *xc_coredump_dir = NULL;
68
69static xc_hash_t xc_php_hcache = {0};
70static xc_hash_t xc_php_hentry = {0};
71static xc_hash_t xc_var_hcache = {0};
72static xc_hash_t xc_var_hentry = {0};
73
74static zend_ulong xc_php_ttl    = 0;
75static zend_ulong xc_var_maxttl = 0;
76
77enum { xc_deletes_gc_interval = 120 };
78static zend_ulong xc_php_gc_interval = 0;
79static zend_ulong xc_var_gc_interval = 0;
80
81/* total size */
82static zend_ulong xc_php_size  = 0;
83static zend_ulong xc_var_size  = 0;
84
85static xc_cache_t **xc_php_caches = NULL;
86static xc_cache_t **xc_var_caches = NULL;
87
88static zend_bool xc_initized = 0;
89static zend_compile_file_t *origin_compile_file = NULL;
90static zend_compile_file_t *old_compile_file = NULL;
91static zend_llist_element  *xc_llist_zend_extension = NULL;
92
93static zend_bool xc_test = 0;
94static zend_bool xc_readonly_protection = 0;
95
96zend_bool xc_have_op_array_ctor = 0;
97
98static zend_bool xc_module_gotup = 0;
99static zend_bool xc_zend_extension_gotup = 0;
100static zend_bool xc_zend_extension_faked = 0;
101#if !COMPILE_DL_XCACHE
102#   define zend_extension_entry xcache_zend_extension_entry
103#endif
104ZEND_DLEXPORT zend_extension zend_extension_entry;
105ZEND_DECLARE_MODULE_GLOBALS(xcache);
106/* }}} */
107
108/* any function in *_dmz is only safe be called within locked(single thread) area */
109
110static void xc_php_add_dmz(xc_entry_data_php_t *php) /* {{{ */
111{
112    xc_entry_data_php_t **head = &(php->cache->phps[php->hvalue]);
113    php->next = *head;
114    *head = php;
115    php->cache->phps_count ++;
116}
117/* }}} */
118static xc_entry_data_php_t *xc_php_store_dmz(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
119{
120    xc_entry_data_php_t *stored_php;
121
122    php->hits     = 0;
123    php->refcount = 0;
124    stored_php = xc_processor_store_xc_entry_data_php_t(php TSRMLS_CC);
125    if (stored_php) {
126        xc_php_add_dmz(stored_php);
127        return stored_php;
128    }
129    else {
130        php->cache->ooms ++;
131        return NULL;
132    }
133}
134/* }}} */
135static xc_entry_data_php_t *xc_php_find_dmz(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
136{
137    xc_entry_data_php_t *p;
138    for (p = php->cache->phps[php->hvalue]; p; p = p->next) {
139        if (memcmp(php->md5, p->md5, sizeof(php->md5)) == 0) {
140            p->hits ++;
141            return p;
142        }
143    }
144    return NULL;
145}
146/* }}} */
147static void xc_php_free_dmz(xc_entry_data_php_t *php) /* {{{ */
148{
149    php->cache->mem->handlers->free(php->cache->mem, (xc_entry_data_php_t *)php);
150}
151/* }}} */
152static void xc_php_addref_dmz(xc_entry_data_php_t *php) /* {{{ */
153{
154    php->refcount ++;
155}
156/* }}} */
157static void xc_php_release_dmz(xc_entry_data_php_t *php) /* {{{ */
158{
159    if (-- php->refcount == 0) {
160        xc_entry_data_php_t **pp = &(php->cache->phps[php->hvalue]);
161        xc_entry_data_php_t *p;
162        for (p = *pp; p; pp = &(p->next), p = p->next) {
163            if (memcmp(php->md5, p->md5, sizeof(php->md5)) == 0) {
164                /* unlink */
165                *pp = p->next;
166                xc_php_free_dmz(php);
167                return;
168            }
169        }
170        assert(0);
171    }
172}
173/* }}} */
174
175static inline int xc_entry_equal_dmz(xc_entry_t *a, xc_entry_t *b) /* {{{ */
176{
177    /* this function isn't required but can be in dmz */
178
179    if (a->type != b->type) {
180        return 0;
181    }
182    switch (a->type) {
183        case XC_TYPE_PHP:
184#ifdef HAVE_INODE
185            do {
186                if (a->inode) {
187                    return a->inode == b->inode
188                        && a->device == b->device;
189                }
190            } while(0);
191#endif
192            /* fall */
193
194        case XC_TYPE_VAR:
195            do {
196#ifdef IS_UNICODE
197                if (a->name_type == IS_UNICODE) {
198                    if (a->name.ustr.len != b->name.ustr.len) {
199                        return 0;
200                    }
201                    return memcmp(a->name.ustr.val, b->name.ustr.val, (a->name.ustr.len + 1) * sizeof(UChar)) == 0;
202                }
203                else {
204                    return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
205                }
206#else
207                return memcmp(a->name.str.val, b->name.str.val, a->name.str.len + 1) == 0;
208#endif
209
210            } while(0);
211        default:
212            assert(0);
213    }
214    return 0;
215}
216/* }}} */
217static void xc_entry_add_dmz(xc_entry_t *xce) /* {{{ */
218{
219    xc_entry_t **head = &(xce->cache->entries[xce->hvalue]);
220    xce->next = *head;
221    *head = xce;
222    xce->cache->entries_count ++;
223}
224/* }}} */
225static xc_entry_t *xc_entry_store_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
226{
227    xc_entry_t *stored_xce;
228
229    xce->hits  = 0;
230    xce->ctime = XG(request_time);
231    xce->atime = XG(request_time);
232    stored_xce = xc_processor_store_xc_entry_t(xce TSRMLS_CC);
233    if (stored_xce) {
234        xc_entry_add_dmz(stored_xce);
235        return stored_xce;
236    }
237    else {
238        xce->cache->ooms ++;
239        return NULL;
240    }
241}
242/* }}} */
243static void xc_entry_free_real_dmz(volatile xc_entry_t *xce) /* {{{ */
244{
245    if (xce->type == XC_TYPE_PHP) {
246        xc_php_release_dmz(xce->data.php);
247    }
248    xce->cache->mem->handlers->free(xce->cache->mem, (xc_entry_t *)xce);
249}
250/* }}} */
251static void xc_entry_free_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
252{
253    xce->cache->entries_count --;
254    if (xce->refcount == 0) {
255        xc_entry_free_real_dmz(xce);
256    }
257    else {
258        xce->next = xce->cache->deletes;
259        xce->cache->deletes = xce;
260        xce->dtime = XG(request_time);
261        xce->cache->deletes_count ++;
262    }
263    return;
264}
265/* }}} */
266static void xc_entry_remove_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
267{
268    xc_entry_t **pp = &(xce->cache->entries[xce->hvalue]);
269    xc_entry_t *p;
270    for (p = *pp; p; pp = &(p->next), p = p->next) {
271        if (xc_entry_equal_dmz(xce, p)) {
272            /* unlink */
273            *pp = p->next;
274            xc_entry_free_dmz(xce TSRMLS_CC);
275            return;
276        }
277    }
278    assert(0);
279}
280/* }}} */
281static xc_entry_t *xc_entry_find_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
282{
283    xc_entry_t *p;
284    for (p = xce->cache->entries[xce->hvalue]; p; p = p->next) {
285        if (xc_entry_equal_dmz(xce, p)) {
286            if (p->type == XC_TYPE_VAR || /* PHP */ p->mtime == xce->mtime) {
287                p->hits ++;
288                p->atime = XG(request_time);
289                return p;
290            }
291            else {
292                xc_entry_remove_dmz(p TSRMLS_CC);
293                return NULL;
294            }
295        }
296    }
297    return NULL;
298}
299/* }}} */
300static void xc_entry_hold_php_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
301{
302    TRACE("hold %s", xce->name.str.val);
303    xce->refcount ++;
304    xc_stack_push(&XG(php_holds)[xce->cache->cacheid], (void *)xce);
305}
306/* }}} */
307#if 0
308static void xc_entry_hold_var_dmz(xc_entry_t *xce TSRMLS_DC) /* {{{ */
309{
310    xce->refcount ++;
311    xc_stack_push(&XG(var_holds)[xce->cache->cacheid], (void *)xce);
312}
313/* }}} */
314#endif
315static inline zend_uint advance_wrapped(zend_uint val, zend_uint count) /* {{{ */
316{
317    if (val + 1 >= count) {
318        return 0;
319    }
320    return val + 1;
321}
322/* }}} */
323static void xc_counters_inc(time_t *curtime, zend_uint *curslot, time_t period, zend_ulong *counters, zend_uint count TSRMLS_DC) /* {{{ */
324{
325    time_t n = XG(request_time) / period;
326    if (*curtime != n) {
327        zend_uint target_slot = n % count;
328        if (n - *curtime > period) {
329            memset(counters, 0, sizeof(counters[0]) * count);
330        }
331        else {
332            zend_uint slot;
333            for (slot = advance_wrapped(*curslot, count);
334                    slot != target_slot;
335                    slot = advance_wrapped(slot, count)) {
336                counters[slot] = 0;
337            }
338            counters[target_slot] = 0;
339        }
340        *curtime = n;
341        *curslot = target_slot;
342    }
343    counters[*curslot] ++;
344}
345/* }}} */
346static void xc_cache_hit_dmz(xc_cache_t *cache TSRMLS_DC) /* {{{ */
347{
348    cache->hits ++;
349
350    xc_counters_inc(&cache->hits_by_hour_cur_time
351            , &cache->hits_by_hour_cur_slot, 60 * 60
352            , cache->hits_by_hour
353            , sizeof(cache->hits_by_hour) / sizeof(cache->hits_by_hour[0])
354            TSRMLS_CC);
355
356    xc_counters_inc(&cache->hits_by_second_cur_time
357            , &cache->hits_by_second_cur_slot
358            , 1
359            , cache->hits_by_second
360            , sizeof(cache->hits_by_second) / sizeof(cache->hits_by_second[0])
361            TSRMLS_CC);
362}
363/* }}} */
364
365/* helper function that loop through each entry */
366#define XC_ENTRY_APPLY_FUNC(name) int name(xc_entry_t *entry TSRMLS_DC)
367typedef XC_ENTRY_APPLY_FUNC((*cache_apply_dmz_func_t));
368static void xc_entry_apply_dmz(xc_cache_t *cache, cache_apply_dmz_func_t apply_func TSRMLS_DC) /* {{{ */
369{
370    xc_entry_t *p, **pp;
371    int i, c;
372
373    for (i = 0, c = cache->hentry->size; i < c; i ++) {
374        pp = &(cache->entries[i]);
375        for (p = *pp; p; p = *pp) {
376            if (apply_func(p TSRMLS_CC)) {
377                /* unlink */
378                *pp = p->next;
379                xc_entry_free_dmz(p TSRMLS_CC);
380            }
381            else {
382                pp = &(p->next);
383            }
384        }
385    }
386}
387/* }}} */
388
389#define XC_CACHE_APPLY_FUNC(name) void name(xc_cache_t *cache TSRMLS_DC)
390/* call graph:
391 * xc_gc_expires_php -> xc_gc_expires_one -> xc_entry_apply_dmz -> xc_gc_expires_php_entry_dmz
392 * xc_gc_expires_var -> xc_gc_expires_one -> xc_entry_apply_dmz -> xc_gc_expires_var_entry_dmz
393 */
394static XC_ENTRY_APPLY_FUNC(xc_gc_expires_php_entry_dmz) /* {{{ */
395{
396    TRACE("ttl %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) entry->atime, xc_php_ttl);
397    if (XG(request_time) > entry->atime + xc_php_ttl) {
398        return 1;
399    }
400    return 0;
401}
402/* }}} */
403static XC_ENTRY_APPLY_FUNC(xc_gc_expires_var_entry_dmz) /* {{{ */
404{
405    if (VAR_ENTRY_EXPIRED(entry)) {
406        return 1;
407    }
408    return 0;
409}
410/* }}} */
411static void xc_gc_expires_one(xc_cache_t *cache, zend_ulong gc_interval, cache_apply_dmz_func_t apply_func TSRMLS_DC) /* {{{ */
412{
413    TRACE("interval %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) cache->last_gc_expires, gc_interval);
414    if (XG(request_time) - cache->last_gc_expires >= gc_interval) {
415        ENTER_LOCK(cache) {
416            if (XG(request_time) - cache->last_gc_expires >= gc_interval) {
417                cache->last_gc_expires = XG(request_time);
418                xc_entry_apply_dmz(cache, apply_func TSRMLS_CC);
419            }
420        } LEAVE_LOCK(cache);
421    }
422}
423/* }}} */
424static void xc_gc_expires_php(TSRMLS_D) /* {{{ */
425{
426    int i, c;
427
428    if (!xc_php_ttl || !xc_php_gc_interval || !xc_php_caches) {
429        return;
430    }
431
432    for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
433        xc_gc_expires_one(xc_php_caches[i], xc_php_gc_interval, xc_gc_expires_php_entry_dmz TSRMLS_CC);
434    }
435}
436/* }}} */
437static void xc_gc_expires_var(TSRMLS_D) /* {{{ */
438{
439    int i, c;
440
441    if (!xc_var_gc_interval || !xc_var_caches) {
442        return;
443    }
444
445    for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
446        xc_gc_expires_one(xc_var_caches[i], xc_var_gc_interval, xc_gc_expires_var_entry_dmz TSRMLS_CC);
447    }
448}
449/* }}} */
450
451static XC_CACHE_APPLY_FUNC(xc_gc_delete_dmz) /* {{{ */
452{
453    xc_entry_t *p, **pp;
454
455    pp = &cache->deletes;
456    for (p = *pp; p; p = *pp) {
457        if (XG(request_time) - p->dtime > 3600) {
458            p->refcount = 0;
459            /* issue warning here */
460        }
461        if (p->refcount == 0) {
462            /* unlink */
463            *pp = p->next;
464            cache->deletes_count --;
465            xc_entry_free_real_dmz(p);
466        }
467        else {
468            pp = &(p->next);
469        }
470    }
471}
472/* }}} */
473static XC_CACHE_APPLY_FUNC(xc_gc_deletes_one) /* {{{ */
474{
475    if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
476        ENTER_LOCK(cache) {
477            if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) {
478                cache->last_gc_deletes = XG(request_time);
479                xc_gc_delete_dmz(cache TSRMLS_CC);
480            }
481        } LEAVE_LOCK(cache);
482    }
483}
484/* }}} */
485static void xc_gc_deletes(TSRMLS_D) /* {{{ */
486{
487    int i, c;
488
489    if (xc_php_caches) {
490        for (i = 0, c = xc_php_hcache.size; i < c; i ++) {
491            xc_gc_deletes_one(xc_php_caches[i] TSRMLS_CC);
492        }
493    }
494
495    if (xc_var_caches) {
496        for (i = 0, c = xc_var_hcache.size; i < c; i ++) {
497            xc_gc_deletes_one(xc_var_caches[i] TSRMLS_CC);
498        }
499    }
500}
501/* }}} */
502
503/* helper functions for user functions */
504static void xc_fillinfo_dmz(int cachetype, xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
505{
506    zval *blocks, *hits;
507    int i;
508    const xc_block_t *b;
509#ifndef NDEBUG
510    xc_memsize_t avail = 0;
511#endif
512    xc_mem_t *mem = cache->mem;
513    const xc_mem_handlers_t *handlers = mem->handlers;
514    zend_ulong interval;
515    if (cachetype == XC_TYPE_PHP) {
516        interval = xc_php_ttl ? xc_php_gc_interval : 0;
517    }
518    else {
519        interval = xc_var_gc_interval;
520    }
521
522    add_assoc_long_ex(return_value, ZEND_STRS("slots"),     cache->hentry->size);
523    add_assoc_long_ex(return_value, ZEND_STRS("compiling"), cache->compiling);
524    add_assoc_long_ex(return_value, ZEND_STRS("misses"),    cache->misses);
525    add_assoc_long_ex(return_value, ZEND_STRS("hits"),      cache->hits);
526    add_assoc_long_ex(return_value, ZEND_STRS("clogs"),     cache->clogs);
527    add_assoc_long_ex(return_value, ZEND_STRS("ooms"),      cache->ooms);
528    add_assoc_long_ex(return_value, ZEND_STRS("errors"),    cache->errors);
529
530    add_assoc_long_ex(return_value, ZEND_STRS("cached"),    cache->entries_count);
531    add_assoc_long_ex(return_value, ZEND_STRS("deleted"),   cache->deletes_count);
532    if (interval) {
533        time_t gc = (cache->last_gc_expires + interval) - XG(request_time);
534        add_assoc_long_ex(return_value, ZEND_STRS("gc"),    gc > 0 ? gc : 0);
535    }
536    else {
537        add_assoc_null_ex(return_value, ZEND_STRS("gc"));
538    }
539    MAKE_STD_ZVAL(hits);
540    array_init(hits);
541    for (i = 0; i < sizeof(cache->hits_by_hour) / sizeof(cache->hits_by_hour[0]); i ++) {
542        add_next_index_long(hits, (long) cache->hits_by_hour[i]);
543    }
544    add_assoc_zval_ex(return_value, ZEND_STRS("hits_by_hour"), hits);
545
546    MAKE_STD_ZVAL(hits);
547    array_init(hits);
548    for (i = 0; i < sizeof(cache->hits_by_second) / sizeof(cache->hits_by_second[0]); i ++) {
549        add_next_index_long(hits, (long) cache->hits_by_second[i]);
550    }
551    add_assoc_zval_ex(return_value, ZEND_STRS("hits_by_second"), hits);
552
553    MAKE_STD_ZVAL(blocks);
554    array_init(blocks);
555
556    add_assoc_long_ex(return_value, ZEND_STRS("size"),  handlers->size(mem));
557    add_assoc_long_ex(return_value, ZEND_STRS("avail"), handlers->avail(mem));
558    add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection);
559
560    for (b = handlers->freeblock_first(mem); b; b = handlers->freeblock_next(b)) {
561        zval *bi;
562
563        MAKE_STD_ZVAL(bi);
564        array_init(bi);
565
566        add_assoc_long_ex(bi, ZEND_STRS("size"),   handlers->block_size(b));
567        add_assoc_long_ex(bi, ZEND_STRS("offset"), handlers->block_offset(mem, b));
568        add_next_index_zval(blocks, bi);
569#ifndef NDEBUG
570        avail += handlers->block_size(b);
571#endif
572    }
573    add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks);
574    assert(avail == handlers->avail(mem));
575}
576/* }}} */
577static void xc_fillentry_dmz(xc_entry_t *entry, int del, zval *list TSRMLS_DC) /* {{{ */
578{
579    zval* ei;
580    xc_entry_data_php_t *php;
581    xc_entry_data_var_t *var;
582
583    ALLOC_INIT_ZVAL(ei);
584    array_init(ei);
585
586    add_assoc_long_ex(ei, ZEND_STRS("refcount"), entry->refcount);
587    add_assoc_long_ex(ei, ZEND_STRS("hits"),     entry->hits);
588    add_assoc_long_ex(ei, ZEND_STRS("ctime"),    entry->ctime);
589    add_assoc_long_ex(ei, ZEND_STRS("atime"),    entry->atime);
590    add_assoc_long_ex(ei, ZEND_STRS("hvalue"),   entry->hvalue);
591    if (del) {
592        add_assoc_long_ex(ei, ZEND_STRS("dtime"), entry->dtime);
593    }
594#ifdef IS_UNICODE
595    do {
596        zval *zv;
597        ALLOC_INIT_ZVAL(zv);
598        switch (entry->name_type) {
599            case IS_UNICODE:
600                    ZVAL_UNICODEL(zv, entry->name.ustr.val, entry->name.ustr.len, 1);
601                break;
602            case IS_STRING:
603                ZVAL_STRINGL(zv, entry->name.str.val, entry->name.str.len, 1);
604                break;
605            default:
606                assert(0);
607        }
608        zv->type = entry->name_type;
609        add_assoc_zval_ex(ei, ZEND_STRS("name"), zv);
610    } while (0);
611#else
612    add_assoc_stringl_ex(ei, ZEND_STRS("name"), entry->name.str.val, entry->name.str.len, 1);
613#endif
614    switch (entry->type) {
615        case XC_TYPE_PHP:
616            php = entry->data.php;
617            add_assoc_long_ex(ei, ZEND_STRS("size"),          entry->size + php->size);
618            add_assoc_long_ex(ei, ZEND_STRS("phprefcount"),   php->refcount);
619            add_assoc_long_ex(ei, ZEND_STRS("sourcesize"),    php->sourcesize);
620#ifdef HAVE_INODE
621            add_assoc_long_ex(ei, ZEND_STRS("device"),        entry->device);
622            add_assoc_long_ex(ei, ZEND_STRS("inode"),         entry->inode);
623#endif
624            add_assoc_long_ex(ei, ZEND_STRS("mtime"),         entry->mtime);
625
626#ifdef HAVE_XCACHE_CONSTANT
627            add_assoc_long_ex(ei, ZEND_STRS("constinfo_cnt"), php->constinfo_cnt);
628#endif
629            add_assoc_long_ex(ei, ZEND_STRS("function_cnt"),  php->funcinfo_cnt);
630            add_assoc_long_ex(ei, ZEND_STRS("class_cnt"),     php->classinfo_cnt);
631#ifdef ZEND_ENGINE_2_1
632            add_assoc_long_ex(ei, ZEND_STRS("autoglobal_cnt"),php->autoglobal_cnt);
633#endif
634            break;
635
636        case XC_TYPE_VAR:
637            var = entry->data.var;
638            add_assoc_long_ex(ei, ZEND_STRS("size"),          entry->size);
639            break;
640
641        default:
642            assert(0);
643    }
644
645    add_next_index_zval(list, ei);
646}
647/* }}} */
648static void xc_filllist_dmz(xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */
649{
650    zval* list;
651    int i, c;
652    xc_entry_t *e;
653
654    ALLOC_INIT_ZVAL(list);
655    array_init(list);
656
657    for (i = 0, c = cache->hentry->size; i < c; i ++) {
658        for (e = cache->entries[i]; e; e = e->next) {
659            xc_fillentry_dmz(e, 0, list TSRMLS_CC);
660        }
661    }
662    add_assoc_zval(return_value, "cache_list", list);
663
664    ALLOC_INIT_ZVAL(list);
665    array_init(list);
666    for (e = cache->deletes; e; e = e->next) {
667        xc_fillentry_dmz(e, 1, list TSRMLS_CC);
668    }
669    add_assoc_zval(return_value, "deleted_list", list);
670}
671/* }}} */
672
673static zend_op_array *xc_entry_install(xc_entry_t *xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
674{
675    zend_uint i;
676    xc_entry_data_php_t *p = xce->data.php;
677    zend_op_array *old_active_op_array = CG(active_op_array);
678#ifndef ZEND_ENGINE_2
679    ALLOCA_FLAG(use_heap)
680    /* new ptr which is stored inside CG(class_table) */
681    xc_cest_t **new_cest_ptrs = (xc_cest_t **)my_do_alloca(sizeof(xc_cest_t*) * p->classinfo_cnt, use_heap);
682#endif
683
684    CG(active_op_array) = p->op_array;
685
686#ifdef HAVE_XCACHE_CONSTANT
687    /* install constant */
688    for (i = 0; i < p->constinfo_cnt; i ++) {
689        xc_constinfo_t *ci = &p->constinfos[i];
690        xc_install_constant(xce->name.str.val, &ci->constant,
691                UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC);
692    }
693#endif
694
695    /* install function */
696    for (i = 0; i < p->funcinfo_cnt; i ++) {
697        xc_funcinfo_t  *fi = &p->funcinfos[i];
698        xc_install_function(xce->name.str.val, &fi->func,
699                UNISW(0, fi->type), fi->key, fi->key_size, fi->h TSRMLS_CC);
700    }
701
702    /* install class */
703    for (i = 0; i < p->classinfo_cnt; i ++) {
704        xc_classinfo_t *ci = &p->classinfos[i];
705#ifndef ZEND_ENGINE_2
706        zend_class_entry *ce = CestToCePtr(ci->cest);
707        /* fix pointer to the be which inside class_table */
708        if (ce->parent) {
709            zend_uint class_idx = (/* class_num */ (int) (long) ce->parent) - 1;
710            assert(class_idx < i);
711            ci->cest.parent = new_cest_ptrs[class_idx];
712        }
713        new_cest_ptrs[i] =
714#endif
715        xc_install_class(xce->name.str.val, &ci->cest, ci->oplineno,
716                UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC);
717    }
718
719#ifdef ZEND_ENGINE_2_1
720    /* trigger auto_globals jit */
721    for (i = 0; i < p->autoglobal_cnt; i ++) {
722        xc_autoglobal_t *aginfo = &p->autoglobals[i];
723        /*
724        zend_auto_global *auto_global;
725        if (zend_u_hash_quick_find(CG(auto_globals), aginfo->type, aginfo->key, aginfo->key_len+1, aginfo->h, (void **) &auto_global)==SUCCESS) {
726            if (auto_global->armed) {
727                auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC);
728            }
729        }
730        */
731        zend_u_is_auto_global(aginfo->type, aginfo->key, aginfo->key_len TSRMLS_CC);
732    }
733#endif
734#ifdef E_STRICT
735    /* restore trigger errors */
736    for (i = 0; i < p->compilererror_cnt; i ++) {
737        xc_compilererror_t *error = &p->compilererrors[i];
738        CG(zend_lineno) = error->lineno;
739        zend_error(E_STRICT, "%s", error->error);
740    }
741    CG(zend_lineno) = 0;
742#endif
743
744    i = 1;
745    zend_hash_add(&EG(included_files), xce->name.str.val, xce->name.str.len+1, (void *)&i, sizeof(int), NULL);
746    if (h) {
747        zend_llist_add_element(&CG(open_files), h);
748    }
749
750#ifndef ZEND_ENGINE_2
751    my_free_alloca(new_cest_ptrs, use_heap);
752#endif
753    CG(active_op_array) = old_active_op_array;
754    return p->op_array;
755}
756/* }}} */
757
758static inline void xc_entry_unholds_real(xc_stack_t *holds, xc_cache_t **caches, int cachecount TSRMLS_DC) /* {{{ */
759{
760    int i;
761    xc_stack_t *s;
762    xc_cache_t *cache;
763    xc_entry_t *xce;
764
765    for (i = 0; i < cachecount; i ++) {
766        s = &holds[i];
767        TRACE("holded %d", xc_stack_count(s));
768        if (xc_stack_count(s)) {
769            cache = ((xc_entry_t *)xc_stack_top(s))->cache;
770            ENTER_LOCK(cache) {
771                while (xc_stack_count(s)) {
772                    xce = (xc_entry_t*) xc_stack_pop(s);
773                    TRACE("unhold %s", xce->name.str.val);
774                    xce->refcount --;
775                    assert(xce->refcount >= 0);
776                }
777            } LEAVE_LOCK(cache);
778        }
779    }
780}
781/* }}} */
782static void xc_entry_unholds(TSRMLS_D) /* {{{ */
783{
784    if (xc_php_caches) {
785        xc_entry_unholds_real(XG(php_holds), xc_php_caches, xc_php_hcache.size TSRMLS_CC);
786    }
787
788    if (xc_var_caches) {
789        xc_entry_unholds_real(XG(var_holds), xc_var_caches, xc_var_hcache.size TSRMLS_CC);
790    }
791}
792/* }}} */
793static int xc_stat(const char *filename, const char *include_path, struct stat *pbuf TSRMLS_DC) /* {{{ */
794{
795    char filepath[MAXPATHLEN];
796    char *paths, *path;
797    char *tokbuf;
798    int size = strlen(include_path) + 1;
799    char tokens[] = { DEFAULT_DIR_SEPARATOR, '\0' };
800    ALLOCA_FLAG(use_heap)
801
802    paths = (char *)my_do_alloca(size, use_heap);
803    memcpy(paths, include_path, size);
804
805    for (path = php_strtok_r(paths, tokens, &tokbuf); path; path = php_strtok_r(NULL, tokens, &tokbuf)) {
806        if (snprintf(filepath, sizeof(filepath), "%s/%s", path, filename) >= MAXPATHLEN - 1) {
807            continue;
808        }
809        if (VCWD_STAT(filepath, pbuf) == 0) {
810            my_free_alloca(paths, use_heap);
811            return SUCCESS;
812        }
813    }
814
815    my_free_alloca(paths, use_heap);
816
817    return FAILURE;
818}
819/* }}} */
820
821#define HASH(i) (i)
822#define HASH_USTR_L(t, s, l) HASH(zend_u_inline_hash_func(t, s, (l + 1) * sizeof(UChar)))
823#define HASH_STR_S(s, l) HASH(zend_inline_hash_func(s, l))
824#define HASH_STR_L(s, l) HASH_STR_S(s, l + 1)
825#define HASH_STR(s) HASH_STR_L(s, strlen(s) + 1)
826#define HASH_NUM(n) HASH(n)
827static inline xc_hash_value_t xc_hash_fold(xc_hash_value_t hvalue, const xc_hash_t *hasher) /* {{{ fold hash bits as needed */
828{
829    xc_hash_value_t folded = 0;
830    while (hvalue) {
831        folded ^= (hvalue & hasher->mask);
832        hvalue >>= hasher->bits;
833    }
834    return folded;
835}
836/* }}} */
837static inline xc_hash_value_t xc_entry_hash_name(xc_entry_t *xce TSRMLS_DC) /* {{{ */
838{
839    return UNISW(NOTHING, UG(unicode) ? HASH_USTR_L(xce->name_type, xce->name.uni.val, xce->name.uni.len) :)
840        HASH_STR_L(xce->name.str.val, xce->name.str.len);
841}
842/* }}} */
843#define xc_entry_hash_var xc_entry_hash_name
844static inline xc_hash_value_t xc_entry_hash_php(xc_entry_t *xce TSRMLS_DC) /* {{{ */
845{
846#ifdef HAVE_INODE
847    if (xce->inode) {
848        return HASH(xce->device + xce->inode);
849    }
850#endif
851    return xc_entry_hash_name(xce TSRMLS_CC);
852}
853/* }}} */
854static int xc_entry_init_key_php(xc_entry_t *xce, char *filename, char *opened_path_buffer TSRMLS_DC) /* {{{ */
855{
856    struct stat buf, *pbuf;
857    xc_hash_value_t hv;
858    int cacheid;
859    xc_entry_data_php_t *php;
860    char *ptr;
861    time_t delta;
862
863    if (!filename || !SG(request_info).path_translated) {
864        return FAILURE;
865    }
866
867    if (strstr(filename, "://") != NULL) {
868        return FAILURE;
869    }
870
871    php = xce->data.php;
872
873    if (XG(stat)) {
874        if (strcmp(SG(request_info).path_translated, filename) == 0) {
875            /* sapi has already done this stat() for us */
876            pbuf = sapi_get_stat(TSRMLS_C);
877            if (pbuf) {
878                goto stat_done;
879            }
880        }
881
882        /* absolute path */
883        pbuf = &buf;
884        if (IS_ABSOLUTE_PATH(filename, strlen(filename))) {
885            if (VCWD_STAT(filename, pbuf) != 0) {
886                return FAILURE;
887            }
888            goto stat_done;
889        }
890
891        /* relative path */
892        if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) {
893            ptr = filename + 1;
894            if (*ptr == '.') {
895                while (*(++ptr) == '.');
896                if (!IS_SLASH(*ptr)) {
897                    goto not_relative_path;
898                }   
899            }
900
901            if (VCWD_STAT(filename, pbuf) != 0) {
902                return FAILURE;
903            }
904            goto stat_done;
905        }
906not_relative_path:
907
908        /* use include_path */
909        if (xc_stat(filename, PG(include_path), pbuf TSRMLS_CC) != SUCCESS) {
910            return FAILURE;
911        }
912
913        /* fall */
914
915stat_done:
916        delta = XG(request_time) - pbuf->st_mtime;
917        if (abs(delta) < 2 && !xc_test) {
918            return FAILURE;
919        }
920
921        xce->mtime        = pbuf->st_mtime;
922#ifdef HAVE_INODE
923        xce->device       = pbuf->st_dev;
924        xce->inode        = pbuf->st_ino;
925#endif
926        php->sourcesize   = pbuf->st_size;
927    }
928    else { /* XG(inode) */
929        xce->mtime        = 0;
930#ifdef HAVE_INODE
931        xce->device       = 0;
932        xce->inode        = 0;
933#endif
934        php->sourcesize   = 0;
935    }
936
937#ifdef HAVE_INODE
938    if (!xce->inode)
939#endif
940    {
941        /* hash on filename, let's expand it to real path */
942        filename = expand_filepath(filename, opened_path_buffer TSRMLS_CC);
943        if (filename == NULL) {
944            return FAILURE;
945        }
946    }
947
948    UNISW(NOTHING, xce->name_type = IS_STRING;)
949    xce->name.str.val = filename;
950    xce->name.str.len = strlen(filename);
951
952    hv = xc_entry_hash_php(xce TSRMLS_CC);
953    cacheid = xc_hash_fold(hv, &xc_php_hcache);
954    xce->cache = xc_php_caches[cacheid];
955    xce->hvalue = xc_hash_fold(hv, &xc_php_hentry);
956
957    xce->type = XC_TYPE_PHP;
958    return SUCCESS;
959}
960/* }}} */
961static inline xc_hash_value_t xc_php_hash_md5(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
962{
963    return HASH_STR_S(php->md5, sizeof(php->md5));
964}
965/* }}} */
966static int xc_entry_init_key_php_md5(xc_entry_data_php_t *php, xc_entry_t *xce TSRMLS_DC) /* {{{ */
967{
968    unsigned char   buf[1024];
969    PHP_MD5_CTX     context;
970    int             n;
971    php_stream     *stream;
972    xc_hash_value_t hv;
973    ulong           old_rsid = EG(regular_list).nNextFreeElement;
974
975    stream = php_stream_open_wrapper(xce->name.str.val, "rb", USE_PATH | REPORT_ERRORS | ENFORCE_SAFE_MODE | STREAM_DISABLE_OPEN_BASEDIR, NULL);
976    if (!stream) {
977        return FAILURE;
978    }
979
980    PHP_MD5Init(&context);
981    while ((n = php_stream_read(stream, (char *) buf, sizeof(buf))) > 0) {
982        PHP_MD5Update(&context, buf, n);
983    }
984    PHP_MD5Final((unsigned char *) php->md5, &context);
985
986    php_stream_close(stream);
987    if (EG(regular_list).nNextFreeElement == old_rsid + 1) {
988        EG(regular_list).nNextFreeElement = old_rsid;
989    }
990
991    if (n < 0) {
992        return FAILURE;
993    }
994
995    hv = xc_php_hash_md5(php TSRMLS_CC);
996    php->cache  = xce->cache;
997    php->hvalue = (hv & php->cache->hphp->mask);
998#ifdef DEBUG
999    {
1000        char md5str[33];
1001        make_digest(md5str, (unsigned char *) php->md5);
1002        TRACE("md5 %s", md5str);
1003    }
1004#endif
1005
1006    return SUCCESS;
1007}
1008/* }}} */
1009static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */
1010{
1011    char *class_name;
1012    int i, class_len;
1013    xc_cest_t cest;
1014    xc_entry_data_php_t *php = (xc_entry_data_php_t *) data;
1015
1016    class_name = opline->op1.u.constant.value.str.val;
1017    class_len  = opline->op1.u.constant.value.str.len;
1018    if (zend_hash_find(CG(class_table), class_name, class_len, (void **) &cest) == FAILURE) {
1019        assert(0);
1020    }
1021    TRACE("got ZEND_DECLARE_INHERITED_CLASS: %s", class_name + 1);
1022    /* let's see which class */
1023    for (i = 0; i < php->classinfo_cnt; i ++) {
1024        if (memcmp(ZSTR_S(php->classinfos[i].key), class_name, class_len) == 0) {
1025            php->classinfos[i].oplineno = oplineno;
1026            php->have_early_binding = 1;
1027            break;
1028        }
1029    }
1030
1031    if (i == php->classinfo_cnt) {
1032        assert(0);
1033    }
1034}
1035/* }}} */
1036static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
1037{
1038#define X_FREE(var) do {\
1039    if (php->var) { \
1040        efree(php->var); \
1041    } \
1042} while (0)
1043
1044#ifdef ZEND_ENGINE_2_1
1045    X_FREE(autoglobals);
1046#endif
1047    X_FREE(classinfos);
1048    X_FREE(funcinfos);
1049#ifdef HAVE_XCACHE_CONSTANT
1050    X_FREE(constinfos);
1051#endif
1052#undef X_FREE
1053}
1054/* }}} */
1055static zend_op_array *xc_compile_php(xc_entry_data_php_t *php, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
1056{
1057    zend_op_array *op_array;
1058    int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
1059    int i;
1060    zend_bool catched = 0;
1061
1062    /* {{{ compile */
1063    TRACE("compiling %s", h->opened_path ? h->opened_path : h->filename);
1064
1065    old_classinfo_cnt = zend_hash_num_elements(CG(class_table));
1066    old_funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
1067    old_constinfo_cnt = zend_hash_num_elements(EG(zend_constants));
1068
1069    php->op_array = NULL;
1070    XG(initial_compile_file_called) = 0;
1071    zend_try {
1072        op_array = old_compile_file(h, type TSRMLS_CC);
1073    } zend_catch {
1074        catched = 1;
1075    } zend_end_try();
1076
1077    if (catched) {
1078        goto err_bailout;
1079    }
1080
1081    if (op_array == NULL) {
1082        goto err_op_array;
1083    }
1084
1085    if (!XG(initial_compile_file_called)) {
1086        return op_array;
1087    }
1088
1089    /* }}} */
1090    /* {{{ prepare */
1091    php->op_array      = op_array;
1092
1093#ifdef HAVE_XCACHE_CONSTANT
1094    php->constinfo_cnt  = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
1095#endif
1096    php->funcinfo_cnt   = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
1097    php->classinfo_cnt  = zend_hash_num_elements(CG(class_table))    - old_classinfo_cnt;
1098#ifdef ZEND_ENGINE_2_1
1099    /* {{{ count php->autoglobal_cnt */ {
1100        Bucket *b;
1101
1102        php->autoglobal_cnt = 0;
1103        for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
1104            zend_auto_global *auto_global = (zend_auto_global *) b->pData;
1105            /* check if actived */
1106            if (auto_global->auto_global_callback && !auto_global->armed) {
1107                php->autoglobal_cnt ++;
1108            }
1109        }
1110    }
1111    /* }}} */
1112#endif
1113
1114#define X_ALLOC_N(var, cnt) do {     \
1115    if (php->cnt) {                  \
1116        ECALLOC_N(php->var, php->cnt); \
1117        if (!php->var) {             \
1118            goto err_alloc;          \
1119        }                            \
1120    }                                \
1121    else {                           \
1122        php->var = NULL;             \
1123    }                                \
1124} while (0)
1125
1126#ifdef HAVE_XCACHE_CONSTANT
1127    X_ALLOC_N(constinfos,  constinfo_cnt);
1128#endif
1129    X_ALLOC_N(funcinfos,   funcinfo_cnt);
1130    X_ALLOC_N(classinfos,  classinfo_cnt);
1131#ifdef ZEND_ENGINE_2_1
1132    X_ALLOC_N(autoglobals, autoglobal_cnt);
1133#endif
1134#undef X_ALLOC
1135    /* }}} */
1136    /* {{{ shallow copy, pointers only */ {
1137        Bucket *b;
1138        unsigned int i;
1139        unsigned int j;
1140
1141#define COPY_H(vartype, var, cnt, name, datatype) do {        \
1142    for (i = 0, j = 0; b; i ++, b = b->pListNext) {           \
1143        vartype *data = &php->var[j];                         \
1144                                                              \
1145        if (i < old_##cnt) {                                  \
1146            continue;                                         \
1147        }                                                     \
1148        j ++;                                                 \
1149                                                              \
1150        assert(i < old_##cnt + php->cnt);                     \
1151        assert(b->pData);                                     \
1152        memcpy(&data->name, b->pData, sizeof(datatype));      \
1153        UNISW(NOTHING, data->type = b->key.type;)             \
1154        if (UNISW(1, b->key.type == IS_STRING)) {             \
1155            ZSTR_S(data->key)      = BUCKET_KEY_S(b);         \
1156        }                                                     \
1157        else {                                                \
1158            ZSTR_U(data->key)      = BUCKET_KEY_U(b);         \
1159        }                                                     \
1160        data->key_size   = b->nKeyLength;                     \
1161        data->h          = b->h;                              \
1162    }                                                         \
1163} while(0)
1164
1165#ifdef HAVE_XCACHE_CONSTANT
1166        b = EG(zend_constants)->pListHead; COPY_H(xc_constinfo_t, constinfos, constinfo_cnt, constant, zend_constant);
1167#endif
1168        b = CG(function_table)->pListHead; COPY_H(xc_funcinfo_t,  funcinfos,  funcinfo_cnt,  func,     zend_function);
1169        b = CG(class_table)->pListHead;    COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest,     xc_cest_t);
1170
1171#undef COPY_H
1172
1173        /* for ZE1, cest need to be fixed inside store */
1174
1175#ifdef ZEND_ENGINE_2_1
1176        /* scan for acatived auto globals */
1177        i = 0;
1178        for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
1179            zend_auto_global *auto_global = (zend_auto_global *) b->pData;
1180            /* check if actived */
1181            if (auto_global->auto_global_callback && !auto_global->armed) {
1182                xc_autoglobal_t *data = &php->autoglobals[i];
1183
1184                assert(i < php->autoglobal_cnt);
1185                i ++;
1186                UNISW(NOTHING, data->type = b->key.type;)
1187                if (UNISW(1, b->key.type == IS_STRING)) {
1188                    ZSTR_S(data->key)     = BUCKET_KEY_S(b);
1189                }
1190                else {
1191                    ZSTR_U(data->key)     = BUCKET_KEY_U(b);
1192                }
1193                data->key_len = b->nKeyLength - 1;
1194                data->h       = b->h;
1195            }
1196        }
1197#endif
1198    }
1199    /* }}} */
1200#ifdef E_STRICT
1201    php->compilererrors = ((xc_sandbox_t *) XG(sandbox))->compilererrors;
1202    php->compilererror_cnt = ((xc_sandbox_t *) XG(sandbox))->compilererror_cnt;
1203#endif
1204    /* {{{ find inherited classes that should be early-binding */
1205    php->have_early_binding = 0;
1206    for (i = 0; i < php->classinfo_cnt; i ++) {
1207        php->classinfos[i].oplineno = -1;
1208    }
1209
1210    xc_undo_pass_two(php->op_array TSRMLS_CC);
1211    xc_foreach_early_binding_class(php->op_array, xc_cache_early_binding_class_cb, (void *) php TSRMLS_CC);
1212    xc_redo_pass_two(php->op_array TSRMLS_CC);
1213    /* }}} */
1214
1215    return op_array;
1216
1217err_alloc:
1218    xc_free_php(php TSRMLS_CC);
1219
1220err_bailout:
1221err_op_array:
1222
1223    if (catched) {
1224        zend_bailout();
1225    }
1226
1227    return op_array;
1228}
1229/* }}} */
1230static zend_op_array *xc_compile_restore(xc_entry_t *stored_xce, zend_file_handle *h TSRMLS_DC) /* {{{ */
1231{
1232    zend_op_array *op_array;
1233    xc_entry_t xce;
1234    xc_entry_data_php_t php;
1235    zend_bool catched;
1236
1237    CG(in_compilation)    = 1;
1238    CG(compiled_filename) = stored_xce->name.str.val;
1239    CG(zend_lineno)       = 0;
1240    TRACE("restoring %s", stored_xce->name.str.val);
1241    xc_processor_restore_xc_entry_t(&xce, stored_xce TSRMLS_CC);
1242    xc_processor_restore_xc_entry_data_php_t(&php, xce.data.php, xc_readonly_protection TSRMLS_CC);
1243    xce.data.php = &php;
1244#ifdef SHOW_DPRINT
1245    xc_dprint(&xce, 0 TSRMLS_CC);
1246#endif
1247
1248    catched = 0;
1249    zend_try {
1250        op_array = xc_entry_install(&xce, h TSRMLS_CC);
1251    } zend_catch {
1252        catched = 1;
1253    } zend_end_try();
1254
1255    if (php.constinfos) {
1256        efree(php.constinfos);
1257    }
1258    if (php.funcinfos) {
1259        efree(php.funcinfos);
1260    }
1261    if (php.classinfos) {
1262        efree(php.classinfos);
1263    }
1264
1265    if (catched) {
1266        zend_bailout();
1267    }
1268    CG(in_compilation)    = 0;
1269    CG(compiled_filename) = NULL;
1270    TRACE("restored  %s", stored_xce->name.str.val);
1271    return op_array;
1272}
1273/* }}} */
1274static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
1275{
1276    XG(initial_compile_file_called) = 1;
1277    return origin_compile_file(h, type TSRMLS_CC);
1278}
1279/* }}} */
1280static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
1281{
1282    zend_op_array *op_array;
1283    xc_entry_t xce, *stored_xce;
1284    xc_entry_data_php_t php, *stored_php;
1285    xc_cache_t *cache;
1286    zend_bool gaveup = 0;
1287    zend_bool catched = 0;
1288    zend_bool newlycompiled;
1289    char *filename;
1290    char opened_path_buffer[MAXPATHLEN];
1291    xc_sandbox_t sandbox;
1292
1293    assert(xc_initized);
1294
1295    TRACE("type = %d\n", h->type);
1296    if (!XG(cacher)) {
1297        op_array = old_compile_file(h, type TSRMLS_CC);
1298        return op_array;
1299    }
1300
1301    /* {{{ entry_init_key */
1302    filename = h->opened_path ? h->opened_path : h->filename;
1303    xce.data.php = &php;
1304    if (xc_entry_init_key_php(&xce, filename, opened_path_buffer TSRMLS_CC) != SUCCESS) {
1305        TRACE("failed to init key for %s", filename);
1306        return old_compile_file(h, type TSRMLS_CC);
1307    }
1308    cache = xce.cache;
1309    /* }}} */
1310
1311    /* stale clogs precheck */
1312    if (cache->compiling) {
1313        cache->clogs ++;
1314        return old_compile_file(h, type TSRMLS_CC);
1315    }
1316    /* {{{ entry_lookup/hit/md5_init/php_lookup */
1317    stored_xce = NULL;
1318    stored_php = NULL;
1319    ENTER_LOCK_EX(cache) {
1320        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
1321        if (stored_xce) {
1322            xc_cache_hit_dmz(cache TSRMLS_CC);
1323
1324            TRACE("hit %s, holding", stored_xce->name.str.val);
1325            xc_entry_hold_php_dmz(stored_xce TSRMLS_CC);
1326        }
1327        else {
1328            cache->misses ++;
1329            TRACE("miss %s", xce.name.str.val);
1330
1331            if (xc_entry_init_key_php_md5(&php, &xce TSRMLS_CC) != SUCCESS) {
1332                gaveup = 1;
1333                break;
1334            }
1335
1336            stored_php = xc_php_find_dmz(&php TSRMLS_CC);
1337
1338            /* miss but compiling */
1339            if (!stored_php) {
1340                if (cache->compiling) {
1341                    TRACE("%s", "miss but compiling");
1342                    cache->clogs ++;
1343                    gaveup = 1;
1344                    break;
1345                }
1346                TRACE("%s", "php_lookup miss");
1347            }
1348            else {
1349                TRACE("%s", "php_lookup hit");
1350            }
1351
1352            cache->compiling = XG(request_time);
1353        }
1354    } LEAVE_LOCK_EX(cache);
1355
1356    if (catched) {
1357        cache->compiling = 0;
1358        zend_bailout();
1359    }
1360
1361    /* hit */
1362    if (stored_xce) {
1363        return xc_compile_restore(stored_xce, h TSRMLS_CC);
1364    }
1365
1366    /* gaveup */
1367    if (gaveup) {
1368        return old_compile_file(h, type TSRMLS_CC);
1369    }
1370    /* }}} */
1371    op_array = NULL;
1372    /* {{{ compile */
1373    if (stored_php) {
1374        newlycompiled = 0;
1375        xce.data.php = stored_php;
1376    }
1377    else {
1378        newlycompiled = 1;
1379
1380        /* make compile inside sandbox */
1381        xc_sandbox_init(&sandbox, filename TSRMLS_CC);
1382
1383#ifdef HAVE_XCACHE_CONSTANT
1384        php.constinfos  = NULL;
1385#endif
1386        php.funcinfos   = NULL;
1387        php.classinfos  = NULL;
1388#ifdef ZEND_ENGINE_2_1
1389        php.autoglobals = NULL;
1390#endif
1391        zend_try {
1392            op_array = xc_compile_php(&php, h, type TSRMLS_CC);
1393        } zend_catch {
1394            catched = 1;
1395        } zend_end_try();
1396
1397        if (catched || !op_array) {
1398            goto err_aftersandbox;
1399        }
1400
1401        /* not cachable */
1402        if (!php.op_array) {
1403            cache->compiling = 0;
1404            /* it's not cachable, but don't scare the users with high misses */
1405            cache->misses --;
1406            xc_sandbox_free(&sandbox, XC_InstallNoBinding TSRMLS_CC);
1407            return op_array;
1408        }
1409
1410        xce.data.php = &php;
1411    }
1412    /* }}} */
1413#ifdef HAVE_INODE
1414    /* {{{ path name fix
1415     * inode enabled entry hash/compare on name
1416     * do not update to its name to real pathname
1417     * WARNING: this code is required to be after compile
1418     */
1419    if (xce.inode) {
1420        filename = h->opened_path ? h->opened_path : h->filename;
1421        if (xce.name.str.val != filename) {
1422            xce.name.str.val = filename;
1423            xce.name.str.len = strlen(filename);
1424        }
1425    }
1426    /* }}} */
1427#endif
1428#ifdef SHOW_DPRINT
1429    xc_dprint(&xce, 0 TSRMLS_CC);
1430#endif
1431    stored_xce = NULL;
1432    ENTER_LOCK_EX(cache) { /* {{{ php_store/entry_store */
1433        /* php_store */
1434        if (newlycompiled) {
1435            stored_php = xc_php_store_dmz(&php TSRMLS_CC);
1436            if (!stored_php) {
1437                /* error */
1438                break;
1439            }
1440        }
1441        /* entry_store */
1442        xc_php_addref_dmz(stored_php);
1443        stored_xce = xc_entry_store_dmz(&xce TSRMLS_CC);
1444        if (stored_xce) {
1445            stored_xce->data.php = stored_php;
1446        }
1447        else {
1448            /* error */
1449            xc_php_release_dmz(stored_php);
1450        }
1451    } LEAVE_LOCK_EX(cache);
1452    /* }}} */
1453    TRACE("%s", stored_xce ? "stored" : "store failed");
1454
1455    cache->compiling = 0;
1456    if (catched) {
1457        goto err_aftersandbox;
1458    }
1459
1460    if (newlycompiled) {
1461        xc_free_php(&php TSRMLS_CC);
1462    }
1463
1464    if (stored_xce) {
1465        if (op_array) {
1466#ifdef ZEND_ENGINE_2
1467            destroy_op_array(op_array TSRMLS_CC);
1468#else
1469            destroy_op_array(op_array);
1470#endif
1471            efree(op_array);
1472            h = NULL;
1473        }
1474        if (newlycompiled) {
1475            xc_sandbox_free(&sandbox, XC_NoInstall TSRMLS_CC);
1476        }
1477        return xc_compile_restore(stored_xce, h TSRMLS_CC);
1478    }
1479    else {
1480        if (newlycompiled) {
1481            zend_op_array *old_active_op_array = CG(active_op_array);
1482            /* install it */
1483            CG(active_op_array) = op_array;
1484            xc_sandbox_free(&sandbox, XC_Install TSRMLS_CC);
1485            CG(active_op_array) = old_active_op_array;
1486        }
1487    }
1488    return op_array;
1489
1490err_aftersandbox:
1491    if (newlycompiled) {
1492        xc_free_php(&php TSRMLS_CC);
1493        xc_sandbox_free(&sandbox, XC_NoInstall TSRMLS_CC);
1494    }
1495
1496    if (catched) {
1497        cache->compiling = 0;
1498        cache->errors ++;
1499        zend_bailout();
1500    }
1501    return op_array;
1502}
1503/* }}} */
1504
1505/* gdb helper functions, but N/A for coredump */
1506int xc_is_rw(const void *p) /* {{{ */
1507{
1508    xc_shm_t *shm;
1509    int i;
1510
1511    if (xc_php_caches) {
1512        for (i = 0; i < xc_php_hcache.size; i ++) {
1513            shm = xc_php_caches[i]->shm;
1514            if (shm->handlers->is_readwrite(shm, p)) {
1515                return 1;
1516            }
1517        }
1518    }
1519
1520    if (xc_var_caches) {
1521        for (i = 0; i < xc_var_hcache.size; i ++) {
1522            shm = xc_var_caches[i]->shm;
1523            if (shm->handlers->is_readwrite(shm, p)) {
1524                return 1;
1525            }
1526        }
1527    }
1528    return 0;
1529}
1530/* }}} */
1531int xc_is_ro(const void *p) /* {{{ */
1532{
1533    xc_shm_t *shm;
1534    int i;
1535
1536    if (xc_php_caches) {
1537        for (i = 0; i < xc_php_hcache.size; i ++) {
1538            shm = xc_php_caches[i]->shm;
1539            if (shm->handlers->is_readonly(shm, p)) {
1540                return 1;
1541            }
1542        }
1543    }
1544
1545    if (xc_var_caches) {
1546        for (i = 0; i < xc_var_hcache.size; i ++) {
1547            shm = xc_var_caches[i]->shm;
1548            if (shm->handlers->is_readonly(shm, p)) {
1549                return 1;
1550            }
1551        }
1552    }
1553    return 0;
1554}
1555/* }}} */
1556int xc_is_shm(const void *p) /* {{{ */
1557{
1558    return xc_is_ro(p) || xc_is_rw(p);
1559}
1560/* }}} */
1561
1562#ifdef ZEND_ENGINE_2
1563/* {{{ xc_gc_op_array_t */
1564typedef struct {
1565    zend_uint num_args;
1566    zend_arg_info *arg_info;
1567} xc_gc_op_array_t;
1568/* }}} */
1569void xc_gc_add_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
1570{
1571    xc_gc_op_array_t gc_op_array;
1572    gc_op_array.num_args = op_array->num_args;
1573    gc_op_array.arg_info = op_array->arg_info;
1574#ifdef ZEND_ENGINE_2
1575    zend_hash_next_index_insert(&XG(gc_op_arrays), (void *) &gc_op_array, sizeof(gc_op_array), NULL);
1576#endif
1577}
1578/* }}} */
1579static void xc_gc_op_array(void *pDest) /* {{{ */
1580{
1581    xc_gc_op_array_t *op_array = (xc_gc_op_array_t *) pDest;
1582    zend_uint i;
1583    if (op_array->arg_info) {
1584        for (i = 0; i < op_array->num_args; i++) {
1585            efree((char *) ZSTR_V(op_array->arg_info[i].name));
1586            if (ZSTR_V(op_array->arg_info[i].class_name)) {
1587                efree((char *) ZSTR_V(op_array->arg_info[i].class_name));
1588            }
1589        }
1590        efree(op_array->arg_info);
1591    }
1592}
1593/* }}} */
1594#endif
1595
1596/* module helper function */
1597static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
1598{
1599    typedef struct {
1600        const char *prefix;
1601        zend_uchar (*getsize)();
1602        const char *(*get)(zend_uchar i);
1603    } xc_meminfo_t;
1604    xc_meminfo_t nameinfos[] = {
1605        { "",        xc_get_op_type_count,   xc_get_op_type   },
1606        { "",        xc_get_data_type_count, xc_get_data_type },
1607        { "",        xc_get_opcode_count,    xc_get_opcode    },
1608        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
1609        { NULL, NULL, NULL }
1610    };
1611    xc_meminfo_t* p;
1612    zend_uchar i, count;
1613    char const_name[96];
1614    int const_name_len;
1615    int undefdone = 0;
1616
1617    for (p = nameinfos; p->getsize; p ++) {
1618        count = p->getsize();
1619        for (i = 0; i < count; i ++) {
1620            const char *name = p->get(i);
1621            if (!name) continue;
1622            if (strcmp(name, "UNDEF") == 0) {
1623                if (undefdone) continue;
1624                undefdone = 1;
1625            }
1626            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
1627            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1628        }
1629    }
1630
1631    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1632    zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1633    zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1634    zend_register_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1635    zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
1636    return 0;
1637}
1638/* }}} */
1639static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
1640{
1641    int i;
1642    xc_cache_t *cache;
1643    xc_shm_t *shm;
1644
1645    if (!caches) {
1646        return NULL;
1647    }
1648    shm = NULL;
1649    for (i = 0; i < hcache->size; i ++) {
1650        cache = caches[i];
1651        if (cache) {
1652            if (cache->lck) {
1653                xc_lock_destroy(cache->lck);
1654            }
1655            /* do NOT free
1656            if (cache->entries) {
1657                cache->mem->handlers->free(cache->mem, cache->entries);
1658            }
1659            cache->mem->handlers->free(cache->mem, cache);
1660            */
1661            shm = cache->shm;
1662            shm->handlers->memdestroy(cache->mem);
1663        }
1664    }
1665    free(caches);
1666    return shm;
1667}
1668/* }}} */
1669static xc_cache_t **xc_cache_init(xc_shm_t *shm, xc_hash_t *hcache, xc_hash_t *hentry, xc_hash_t *hphp, xc_shmsize_t shmsize) /* {{{ */
1670{
1671    xc_cache_t **caches = NULL, *cache;
1672    xc_mem_t *mem;
1673    time_t now = time(NULL);
1674    int i;
1675    xc_memsize_t memsize;
1676
1677    memsize = shmsize / hcache->size;
1678
1679    /* Don't let it break out of mem after ALIGNed
1680     * This is important for
1681     * Simply loop until it fit our need
1682     */
1683    while (ALIGN(memsize) * hcache->size > shmsize && ALIGN(memsize) != memsize) {
1684        if (memsize < ALIGN(1)) {
1685            CHECK(NULL, "cache too small");
1686        }
1687        memsize --;
1688    }
1689
1690    CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
1691
1692    for (i = 0; i < hcache->size; i ++) {
1693        CHECK(mem            = shm->handlers->meminit(shm, memsize), "Failed init memory allocator");
1694        CHECK(cache          = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
1695        CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
1696        if (hphp) {
1697            CHECK(cache->phps= mem->handlers->calloc(mem, hphp->size, sizeof(xc_entry_data_php_t*)), "phps OOM");
1698        }
1699        CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
1700
1701        cache->hcache  = hcache;
1702        cache->hentry  = hentry;
1703        cache->hphp    = hphp;
1704        cache->shm     = shm;
1705        cache->mem     = mem;
1706        cache->cacheid = i;
1707        cache->last_gc_deletes = now;
1708        cache->last_gc_expires = now;
1709        caches[i] = cache;
1710    }
1711    return caches;
1712
1713err:
1714    if (caches) {
1715        xc_cache_destroy(caches, hcache);
1716    }
1717    return NULL;
1718}
1719/* }}} */
1720static void xc_destroy() /* {{{ */
1721{
1722    xc_shm_t *shm = NULL;
1723
1724    if (old_compile_file) {
1725        zend_compile_file = old_compile_file;
1726        old_compile_file = NULL;
1727    }
1728
1729    if (origin_compile_file) {
1730        zend_compile_file = origin_compile_file;
1731        origin_compile_file = NULL;
1732    }
1733
1734    if (xc_php_caches) {
1735        shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
1736        xc_php_caches = NULL;
1737    }
1738
1739    if (xc_var_caches) {
1740        shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
1741        xc_var_caches = NULL;
1742    }
1743
1744    if (shm) {
1745        xc_shm_destroy(shm);
1746    }
1747
1748    xc_initized = 0;
1749}
1750/* }}} */
1751static int xc_init(int module_number TSRMLS_DC) /* {{{ */
1752{
1753    xc_shm_t *shm;
1754    xc_shmsize_t shmsize = ALIGN(xc_php_size) + ALIGN(xc_var_size);
1755
1756    xc_php_caches = xc_var_caches = NULL;
1757    shm = NULL;
1758
1759    if (shmsize < (size_t) xc_php_size || shmsize < (size_t) xc_var_size) {
1760        zend_error(E_ERROR, "XCache: neither xcache.size nor xcache.var_size can be negative");
1761        goto err;
1762    }
1763
1764    if (xc_php_size || xc_var_size) {
1765        CHECK(shm = xc_shm_init(xc_shm_scheme, shmsize, xc_readonly_protection, xc_mmap_path, NULL), "Cannot create shm");
1766        if (!shm->handlers->can_readonly(shm)) {
1767            xc_readonly_protection = 0;
1768        }
1769
1770        if (xc_php_size) {
1771            old_compile_file = zend_compile_file;
1772            zend_compile_file = xc_compile_file;
1773
1774            CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, &xc_php_hentry, xc_php_size), "failed init opcode cache");
1775        }
1776
1777        if (xc_var_size) {
1778            CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, NULL, xc_var_size), "failed init variable cache");
1779        }
1780    }
1781    return SUCCESS;
1782
1783err:
1784    if (xc_php_caches || xc_var_caches) {
1785        xc_destroy();
1786        /* shm destroied in xc_destroy() */
1787    }
1788    else if (shm) {
1789        xc_destroy();
1790        xc_shm_destroy(shm);
1791    }
1792    return 0;
1793}
1794/* }}} */
1795static void xc_request_init(TSRMLS_D) /* {{{ */
1796{
1797    int i;
1798
1799    if (!XG(internal_table_copied)) {
1800        zend_function tmp_func;
1801        xc_cest_t tmp_cest;
1802
1803        zend_hash_destroy(&XG(internal_function_table));
1804        zend_hash_destroy(&XG(internal_class_table));
1805
1806        zend_hash_init_ex(&XG(internal_function_table), 100, NULL, NULL, 1, 0);
1807        zend_hash_init_ex(&XG(internal_class_table),    10,  NULL, NULL, 1, 0);
1808
1809        zend_hash_copy(&XG(internal_function_table), CG(function_table), NULL, &tmp_func, sizeof(tmp_func));
1810        zend_hash_copy(&XG(internal_class_table), CG(class_table), NULL, &tmp_cest, sizeof(tmp_cest));
1811
1812        XG(internal_table_copied) = 1;
1813    }
1814    if (xc_php_caches && !XG(php_holds)) {
1815        XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
1816        for (i = 0; i < xc_php_hcache.size; i ++) {
1817            xc_stack_init(&XG(php_holds[i]));
1818        }
1819    }
1820
1821    if (xc_var_caches && !XG(var_holds)) {
1822        XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
1823        for (i = 0; i < xc_var_hcache.size; i ++) {
1824            xc_stack_init(&XG(var_holds[i]));
1825        }
1826    }
1827
1828#ifdef ZEND_ENGINE_2
1829    zend_hash_init(&XG(gc_op_arrays), 32, NULL, xc_gc_op_array, 0);
1830#endif
1831
1832#if PHP_API_VERSION <= 20041225
1833    XG(request_time) = time(NULL);
1834#else
1835    XG(request_time) = sapi_get_request_time(TSRMLS_C);
1836#endif
1837
1838#ifdef HAVE_XCACHE_COVERAGER
1839    xc_coverager_request_init(TSRMLS_C);
1840#endif
1841}
1842/* }}} */
1843static void xc_request_shutdown(TSRMLS_D) /* {{{ */
1844{
1845    xc_entry_unholds(TSRMLS_C);
1846#ifdef ZEND_ENGINE_2
1847    zend_hash_destroy(&XG(gc_op_arrays));
1848#endif
1849    xc_gc_expires_php(TSRMLS_C);
1850    xc_gc_expires_var(TSRMLS_C);
1851    xc_gc_deletes(TSRMLS_C);
1852#ifdef HAVE_XCACHE_COVERAGER
1853    xc_coverager_request_shutdown(TSRMLS_C);
1854#endif
1855}
1856/* }}} */
1857/* {{{ PHP_GINIT_FUNCTION(xcache) */
1858static
1859#ifdef PHP_GINIT_FUNCTION
1860PHP_GINIT_FUNCTION(xcache)
1861#else
1862void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
1863#endif
1864{
1865    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
1866
1867    zend_hash_init_ex(&xcache_globals->internal_function_table, 1, NULL, NULL, 1, 0);
1868    zend_hash_init_ex(&xcache_globals->internal_class_table,    1, NULL, NULL, 1, 0);
1869}
1870/* }}} */
1871/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
1872static
1873#ifdef PHP_GSHUTDOWN_FUNCTION
1874PHP_GSHUTDOWN_FUNCTION(xcache)
1875#else
1876void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
1877#endif
1878{
1879    int i;
1880
1881    if (xcache_globals->php_holds != NULL) {
1882        for (i = 0; i < xc_php_hcache.size; i ++) {
1883            xc_stack_destroy(&xcache_globals->php_holds[i]);
1884        }
1885        free(xcache_globals->php_holds);
1886        xcache_globals->php_holds = NULL;
1887    }
1888
1889    if (xcache_globals->var_holds != NULL) {
1890        for (i = 0; i < xc_var_hcache.size; i ++) {
1891            xc_stack_destroy(&xcache_globals->var_holds[i]);
1892        }
1893        free(xcache_globals->var_holds);
1894        xcache_globals->var_holds = NULL;
1895    }
1896
1897    if (xcache_globals->internal_table_copied) {
1898        zend_hash_destroy(&xcache_globals->internal_function_table);
1899        zend_hash_destroy(&xcache_globals->internal_class_table);
1900    }
1901}
1902/* }}} */
1903
1904/* user functions */
1905static int xcache_admin_auth_check(TSRMLS_D) /* {{{ */
1906{
1907    zval **server = NULL;
1908    zval **user = NULL;
1909    zval **pass = NULL;
1910    char *admin_user = NULL;
1911    char *admin_pass = NULL;
1912    HashTable *ht;
1913
1914    if (cfg_get_string("xcache.admin.user", &admin_user) == FAILURE || !admin_user[0]) {
1915        admin_user = NULL;
1916    }
1917    if (cfg_get_string("xcache.admin.pass", &admin_pass) == FAILURE || !admin_pass[0]) {
1918        admin_pass = NULL;
1919    }
1920
1921    if (admin_user == NULL || admin_pass == NULL) {
1922        php_error_docref(NULL TSRMLS_CC, E_ERROR, "xcache.admin.user and xcache.admin.pass is required");
1923        zend_bailout();
1924    }
1925    if (strlen(admin_pass) != 32) {
1926        php_error_docref(NULL TSRMLS_CC, E_ERROR, "unexpect %lu bytes of xcache.admin.pass, expected 32 bytes, the password after md5()", (unsigned long) strlen(admin_pass));
1927        zend_bailout();
1928    }
1929
1930#ifdef ZEND_ENGINE_2_1
1931    zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
1932#endif
1933    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != SUCCESS || Z_TYPE_PP(server) != IS_ARRAY) {
1934        php_error_docref(NULL TSRMLS_CC, E_ERROR, "_SERVER is corrupted");
1935        zend_bailout();
1936    }
1937    ht = HASH_OF((*server));
1938
1939    if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
1940        user = NULL;
1941    }
1942    else if (Z_TYPE_PP(user) != IS_STRING) {
1943        user = NULL;
1944    }
1945
1946    if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {
1947        pass = NULL;
1948    }
1949    else if (Z_TYPE_PP(pass) != IS_STRING) {
1950        pass = NULL;
1951    }
1952
1953    if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {
1954        PHP_MD5_CTX context;
1955        char md5str[33];
1956        unsigned char digest[16];
1957
1958        PHP_MD5Init(&context);
1959        PHP_MD5Update(&context, (unsigned char *) Z_STRVAL_PP(pass), Z_STRLEN_PP(pass));
1960        PHP_MD5Final(digest, &context);
1961
1962        md5str[0] = '\0';
1963        make_digest(md5str, digest);
1964        if (strcmp(admin_pass, md5str) == 0) {
1965            return 1;
1966        }
1967    }
1968
1969#define STR "WWW-authenticate: Basic Realm=\"XCache Administration\""
1970    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1971#undef STR
1972#define STR "HTTP/1.0 401 Unauthorized"
1973    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
1974#undef STR
1975    ZEND_PUTS("XCache Auth Failed. User and Password is case sense\n");
1976
1977    zend_bailout();
1978    return 0;
1979}
1980/* }}} */
1981/* {{{ xcache_admin_operate */
1982typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
1983static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
1984{
1985    long type;
1986    int size;
1987    xc_cache_t **caches, *cache;
1988    long id = 0;
1989
1990    xcache_admin_auth_check(TSRMLS_C);
1991
1992    if (!xc_initized) {
1993        RETURN_NULL();
1994    }
1995
1996    if (optype == XC_OP_COUNT) {
1997        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
1998            return;
1999        }
2000    }
2001    else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
2002        return;
2003    }
2004
2005    switch (type) {
2006        case XC_TYPE_PHP:
2007            size = xc_php_hcache.size;
2008            caches = xc_php_caches;
2009            break;
2010
2011        case XC_TYPE_VAR:
2012            size = xc_var_hcache.size;
2013            caches = xc_var_caches;
2014            break;
2015
2016        default:
2017            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
2018            RETURN_FALSE;
2019    }
2020
2021    switch (optype) {
2022        case XC_OP_COUNT:
2023            RETURN_LONG(size)
2024            break;
2025
2026        case XC_OP_INFO:
2027        case XC_OP_LIST:
2028            if (id < 0 || id >= size) {
2029                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
2030                RETURN_FALSE;
2031            }
2032
2033            array_init(return_value);
2034
2035            cache = caches[id];
2036            ENTER_LOCK(cache) {
2037                if (optype == XC_OP_INFO) {
2038                    xc_fillinfo_dmz(type, cache, return_value TSRMLS_CC);
2039                }
2040                else {
2041                    xc_filllist_dmz(cache, return_value TSRMLS_CC);
2042                }
2043            } LEAVE_LOCK(cache);
2044            break;
2045        case XC_OP_CLEAR:
2046            {
2047                xc_entry_t *e, *next;
2048                int i, c;
2049
2050                if (id < 0 || id >= size) {
2051                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
2052                    RETURN_FALSE;
2053                }
2054
2055                cache = caches[id];
2056                ENTER_LOCK(cache) {
2057                    for (i = 0, c = cache->hentry->size; i < c; i ++) {
2058                        for (e = cache->entries[i]; e; e = next) {
2059                            next = e->next;
2060                            xc_entry_remove_dmz(e TSRMLS_CC);
2061                        }
2062                        cache->entries[i] = NULL;
2063                    }
2064                } LEAVE_LOCK(cache);
2065                xc_gc_deletes(TSRMLS_C);
2066            }
2067            break;
2068
2069        default:
2070            assert(0);
2071    }
2072}
2073/* }}} */
2074/* {{{ proto int xcache_count(int type)
2075   Return count of cache on specified cache type */
2076PHP_FUNCTION(xcache_count)
2077{
2078    xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2079}
2080/* }}} */
2081/* {{{ proto array xcache_info(int type, int id)
2082   Get cache info by id on specified cache type */
2083PHP_FUNCTION(xcache_info)
2084{
2085    xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2086}
2087/* }}} */
2088/* {{{ proto array xcache_list(int type, int id)
2089   Get cache entries list by id on specified cache type */
2090PHP_FUNCTION(xcache_list)
2091{
2092    xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2093}
2094/* }}} */
2095/* {{{ proto array xcache_clear_cache(int type, int id)
2096   Clear cache by id on specified cache type */
2097PHP_FUNCTION(xcache_clear_cache)
2098{
2099    xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2100}
2101/* }}} */
2102
2103#define VAR_DISABLED_WARNING() do { \
2104        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.var_size is either 0 or too small to enable var data caching"); \
2105} while (0)
2106
2107static int xc_entry_init_key_var(xc_entry_t *xce, zval *name TSRMLS_DC) /* {{{ */
2108{
2109    xc_hash_value_t hv;
2110    int cacheid;
2111
2112    switch (Z_TYPE_P(name)) {
2113#ifdef IS_UNICODE
2114        case IS_UNICODE:
2115#endif
2116        case IS_STRING:
2117            break;
2118        default:
2119#ifdef IS_UNICODE
2120            convert_to_text(name);
2121#else
2122            convert_to_string(name);
2123#endif
2124    }
2125#ifdef IS_UNICODE
2126    xce->name_type = name->type;
2127#endif
2128    xce->name = name->value;
2129
2130    hv = xc_entry_hash_var(xce TSRMLS_CC);
2131
2132    cacheid = (hv & xc_var_hcache.mask);
2133    xce->cache = xc_var_caches[cacheid];
2134    hv >>= xc_var_hcache.bits;
2135    xce->hvalue = (hv & xc_var_hentry.mask);
2136
2137    xce->type = XC_TYPE_VAR;
2138    return SUCCESS;
2139}
2140/* }}} */
2141/* {{{ proto mixed xcache_get(string name)
2142   Get cached data by specified name */
2143PHP_FUNCTION(xcache_get)
2144{
2145    xc_entry_t xce, *stored_xce;
2146    xc_entry_data_var_t var;
2147    zval *name;
2148    int found = 0;
2149
2150    if (!xc_var_caches) {
2151        VAR_DISABLED_WARNING();
2152        RETURN_NULL();
2153    }
2154
2155    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
2156        return;
2157    }
2158    xce.data.var = &var;
2159    xc_entry_init_key_var(&xce, name TSRMLS_CC);
2160
2161    ENTER_LOCK(xce.cache) {
2162        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
2163        if (stored_xce) {
2164            if (!VAR_ENTRY_EXPIRED(stored_xce)) {
2165                found = 1;
2166                xc_processor_restore_zval(return_value, stored_xce->data.var->value, stored_xce->data.var->have_references TSRMLS_CC);
2167                /* return */
2168                break;
2169            }
2170            else {
2171                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
2172            }
2173        }
2174
2175        RETVAL_NULL();
2176    } LEAVE_LOCK(xce.cache);
2177    if (found) {
2178        xc_cache_hit_dmz(xce.cache TSRMLS_CC);
2179    }
2180    else {
2181        xce.cache->misses ++;
2182    }
2183}
2184/* }}} */
2185/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
2186   Store data to cache by specified name */
2187PHP_FUNCTION(xcache_set)
2188{
2189    xc_entry_t xce, *stored_xce;
2190    xc_entry_data_var_t var;
2191    zval *name;
2192    zval *value;
2193
2194    if (!xc_var_caches) {
2195        VAR_DISABLED_WARNING();
2196        RETURN_NULL();
2197    }
2198
2199    xce.ttl = XG(var_ttl);
2200    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &xce.ttl) == FAILURE) {
2201        return;
2202    }
2203
2204    /* max ttl */
2205    if (xc_var_maxttl && (!xce.ttl || xce.ttl > xc_var_maxttl)) {
2206        xce.ttl = xc_var_maxttl;
2207    }
2208
2209    xce.data.var = &var;
2210    xc_entry_init_key_var(&xce, name TSRMLS_CC);
2211
2212    ENTER_LOCK(xce.cache) {
2213        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
2214        if (stored_xce) {
2215            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
2216        }
2217        var.value = value;
2218        RETVAL_BOOL(xc_entry_store_dmz(&xce TSRMLS_CC) != NULL ? 1 : 0);
2219    } LEAVE_LOCK(xce.cache);
2220}
2221/* }}} */
2222/* {{{ proto bool  xcache_isset(string name)
2223   Check if an entry exists in cache by specified name */
2224PHP_FUNCTION(xcache_isset)
2225{
2226    xc_entry_t xce, *stored_xce;
2227    xc_entry_data_var_t var;
2228    zval *name;
2229    int found = 0;
2230
2231    if (!xc_var_caches) {
2232        VAR_DISABLED_WARNING();
2233        RETURN_FALSE;
2234    }
2235
2236    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
2237        return;
2238    }
2239    xce.data.var = &var;
2240    xc_entry_init_key_var(&xce, name TSRMLS_CC);
2241
2242    ENTER_LOCK(xce.cache) {
2243        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
2244        if (stored_xce) {
2245            if (!VAR_ENTRY_EXPIRED(stored_xce)) {
2246                found = 1;
2247                RETVAL_TRUE;
2248                /* return */
2249                break;
2250            }
2251            else {
2252                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
2253            }
2254        }
2255
2256        RETVAL_FALSE;
2257    } LEAVE_LOCK(xce.cache);
2258    if (found) {
2259        xc_cache_hit_dmz(xce.cache TSRMLS_CC);
2260    }
2261    else {
2262        xce.cache->misses ++;
2263    }
2264}
2265/* }}} */
2266/* {{{ proto bool  xcache_unset(string name)
2267   Unset existing data in cache by specified name */
2268PHP_FUNCTION(xcache_unset)
2269{
2270    xc_entry_t xce, *stored_xce;
2271    xc_entry_data_var_t var;
2272    zval *name;
2273
2274    if (!xc_var_caches) {
2275        VAR_DISABLED_WARNING();
2276        RETURN_FALSE;
2277    }
2278
2279    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
2280        return;
2281    }
2282    xce.data.var = &var;
2283    xc_entry_init_key_var(&xce, name TSRMLS_CC);
2284
2285    ENTER_LOCK(xce.cache) {
2286        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
2287        if (stored_xce) {
2288            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
2289            RETVAL_TRUE;
2290        }
2291        else {
2292            RETVAL_FALSE;
2293        }
2294    } LEAVE_LOCK(xce.cache);
2295}
2296/* }}} */
2297static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
2298{
2299    xc_entry_t xce, *stored_xce;
2300    xc_entry_data_var_t var, *stored_var;
2301    zval *name;
2302    long count = 1;
2303    long value = 0;
2304    zval oldzval;
2305
2306    if (!xc_var_caches) {
2307        VAR_DISABLED_WARNING();
2308        RETURN_NULL();
2309    }
2310
2311    xce.ttl = XG(var_ttl);
2312    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &xce.ttl) == FAILURE) {
2313        return;
2314    }
2315
2316    /* max ttl */
2317    if (xc_var_maxttl && (!xce.ttl || xce.ttl > xc_var_maxttl)) {
2318        xce.ttl = xc_var_maxttl;
2319    }
2320
2321    xce.data.var = &var;
2322    xc_entry_init_key_var(&xce, name TSRMLS_CC);
2323
2324    ENTER_LOCK(xce.cache) {
2325        stored_xce = xc_entry_find_dmz(&xce TSRMLS_CC);
2326        if (stored_xce) {
2327            TRACE("incdec: gotxce %s", xce.name.str.val);
2328            /* timeout */
2329            if (VAR_ENTRY_EXPIRED(stored_xce)) {
2330                TRACE("%s", "incdec: expired");
2331                xc_entry_remove_dmz(stored_xce TSRMLS_CC);
2332                stored_xce = NULL;
2333            }
2334            else {
2335                /* do it in place */
2336                stored_var = stored_xce->data.var;
2337                if (Z_TYPE_P(stored_var->value) == IS_LONG) {
2338                    zval *zv;
2339                    stored_xce->ctime = XG(request_time);
2340                    stored_xce->ttl   = xce.ttl;
2341                    TRACE("%s", "incdec: islong");
2342                    value = Z_LVAL_P(stored_var->value);
2343                    value += (inc == 1 ? count : - count);
2344                    RETVAL_LONG(value);
2345
2346                    zv = (zval *) xce.cache->shm->handlers->to_readwrite(xce.cache->shm, (char *) stored_var->value);
2347                    Z_LVAL_P(zv) = value;
2348                    break; /* leave lock */
2349                }
2350                else {
2351                    TRACE("%s", "incdec: notlong");
2352                    xc_processor_restore_zval(&oldzval, stored_xce->data.var->value, stored_xce->data.var->have_references TSRMLS_CC);
2353                    convert_to_long(&oldzval);
2354                    value = Z_LVAL(oldzval);
2355                    zval_dtor(&oldzval);
2356                }
2357            }
2358        }
2359        else {
2360            TRACE("incdec: %s not found", xce.name.str.val);
2361        }
2362
2363        value += (inc == 1 ? count : - count);
2364        RETVAL_LONG(value);
2365        var.value = return_value;
2366
2367        if (stored_xce) {
2368            xce.atime = stored_xce->atime;
2369            xce.ctime = stored_xce->ctime;
2370            xce.hits  = stored_xce->hits;
2371            xc_entry_remove_dmz(stored_xce TSRMLS_CC);
2372        }
2373        xc_entry_store_dmz(&xce TSRMLS_CC);
2374
2375    } LEAVE_LOCK(xce.cache);
2376}
2377/* }}} */
2378/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
2379   Increase an int counter in cache by specified name, create it if not exists */
2380PHP_FUNCTION(xcache_inc)
2381{
2382    xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2383}
2384/* }}} */
2385/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
2386   Decrease an int counter in cache by specified name, create it if not exists */
2387PHP_FUNCTION(xcache_dec)
2388{
2389    xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2390}
2391/* }}} */
2392/* {{{ proto string xcache_asm(string filename)
2393 */
2394#ifdef HAVE_XCACHE_ASSEMBLER
2395PHP_FUNCTION(xcache_asm)
2396{
2397}
2398#endif
2399/* }}} */
2400#ifdef HAVE_XCACHE_DISASSEMBLER
2401/* {{{ proto array  xcache_dasm_file(string filename)
2402   Disassemble file into opcode array by filename */
2403PHP_FUNCTION(xcache_dasm_file)
2404{
2405    char *filename;
2406    int filename_len;
2407
2408    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
2409        return;
2410    }
2411    if (!filename_len) RETURN_FALSE;
2412
2413    xc_dasm_file(return_value, filename TSRMLS_CC);
2414}
2415/* }}} */
2416/* {{{ proto array  xcache_dasm_string(string code)
2417   Disassemble php code into opcode array */
2418PHP_FUNCTION(xcache_dasm_string)
2419{
2420    zval *code;
2421
2422    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
2423        return;
2424    }
2425    xc_dasm_string(return_value, code TSRMLS_CC);
2426}
2427/* }}} */
2428#endif
2429/* {{{ proto string xcache_encode(string filename)
2430   Encode php file into XCache opcode encoded format */
2431#ifdef HAVE_XCACHE_ENCODER
2432PHP_FUNCTION(xcache_encode)
2433{
2434}
2435#endif
2436/* }}} */
2437/* {{{ proto bool xcache_decode_file(string filename)
2438   Decode(load) opcode from XCache encoded format file */
2439#ifdef HAVE_XCACHE_DECODER
2440PHP_FUNCTION(xcache_decode_file)
2441{
2442}
2443#endif
2444/* }}} */
2445/* {{{ proto bool xcache_decode_string(string data)
2446   Decode(load) opcode from XCache encoded format data */
2447#ifdef HAVE_XCACHE_DECODER
2448PHP_FUNCTION(xcache_decode_string)
2449{
2450}
2451#endif
2452/* }}} */
2453/* {{{ xc_call_getter */
2454typedef const char *(xc_name_getter_t)(zend_uchar type);
2455static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
2456{
2457    long spec;
2458    const char *name;
2459
2460    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
2461        return;
2462    }
2463    if (spec >= 0 && spec < count) {
2464        name = getter((zend_uchar) spec);
2465        if (name) {
2466            /* RETURN_STRING */
2467            int len = strlen(name);
2468            return_value->value.str.len = len;
2469            return_value->value.str.val = estrndup(name, len);
2470            return_value->type = IS_STRING; 
2471            return;
2472        }
2473    }
2474    RETURN_NULL();
2475}
2476/* }}} */
2477/* {{{ proto string xcache_get_op_type(int op_type) */
2478PHP_FUNCTION(xcache_get_op_type)
2479{
2480    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
2481}
2482/* }}} */
2483/* {{{ proto string xcache_get_data_type(int type) */
2484PHP_FUNCTION(xcache_get_data_type)
2485{
2486    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
2487}
2488/* }}} */
2489/* {{{ proto string xcache_get_opcode(int opcode) */
2490PHP_FUNCTION(xcache_get_opcode)
2491{
2492    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
2493}
2494/* }}} */
2495/* {{{ proto string xcache_get_op_spec(int op_type) */
2496PHP_FUNCTION(xcache_get_op_spec)
2497{
2498    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
2499}
2500/* }}} */
2501#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
2502/* {{{ proto string xcache_get_opcode_spec(int opcode) */
2503PHP_FUNCTION(xcache_get_opcode_spec)
2504{
2505    long spec;
2506    const xc_opcode_spec_t *opspec;
2507
2508    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
2509        return;
2510    }
2511    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
2512        opspec = xc_get_opcode_spec((zend_uchar) spec);
2513        if (opspec) {
2514            array_init(return_value);
2515            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
2516            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
2517            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
2518            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
2519            return;
2520        }
2521    }
2522    RETURN_NULL();
2523}
2524/* }}} */
2525#endif
2526/* {{{ proto mixed xcache_get_special_value(zval value) */
2527PHP_FUNCTION(xcache_get_special_value)
2528{
2529    zval *value;
2530
2531    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
2532        return;
2533    }
2534
2535    if (value->type == IS_CONSTANT) {
2536        *return_value = *value;
2537        zval_copy_ctor(return_value);
2538        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
2539        return;
2540    }
2541
2542    if (value->type == IS_CONSTANT_ARRAY) {
2543        *return_value = *value;
2544        zval_copy_ctor(return_value);
2545        return_value->type = IS_ARRAY;
2546        return;
2547    }
2548
2549    RETURN_NULL();
2550}
2551/* }}} */
2552/* {{{ proto string xcache_coredump(int op_type) */
2553PHP_FUNCTION(xcache_coredump)
2554{
2555    if (xc_test) {
2556        raise(SIGSEGV);
2557    }
2558    else {
2559        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
2560    }
2561}
2562/* }}} */
2563/* {{{ proto string xcache_is_autoglobal(string name) */
2564PHP_FUNCTION(xcache_is_autoglobal)
2565{
2566    char *name;
2567    int name_len;
2568
2569    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
2570        return;
2571    }
2572
2573    RETURN_BOOL(zend_hash_exists(CG(auto_globals), name, name_len + 1));
2574}
2575/* }}} */
2576static function_entry xcache_functions[] = /* {{{ */
2577{
2578    PHP_FE(xcache_count,             NULL)
2579    PHP_FE(xcache_info,              NULL)
2580    PHP_FE(xcache_list,              NULL)
2581    PHP_FE(xcache_clear_cache,       NULL)
2582    PHP_FE(xcache_coredump,          NULL)
2583#ifdef HAVE_XCACHE_ASSEMBLER
2584    PHP_FE(xcache_asm,               NULL)
2585#endif
2586#ifdef HAVE_XCACHE_DISASSEMBLER
2587    PHP_FE(xcache_dasm_file,         NULL)
2588    PHP_FE(xcache_dasm_string,       NULL)
2589#endif
2590#ifdef HAVE_XCACHE_ENCODER
2591    PHP_FE(xcache_encode,            NULL)
2592#endif
2593#ifdef HAVE_XCACHE_DECODER
2594    PHP_FE(xcache_decode_file,       NULL)
2595    PHP_FE(xcache_decode_string,     NULL)
2596#endif
2597#ifdef HAVE_XCACHE_COVERAGER
2598    PHP_FE(xcache_coverager_decode,  NULL)
2599    PHP_FE(xcache_coverager_start,   NULL)
2600    PHP_FE(xcache_coverager_stop,    NULL)
2601    PHP_FE(xcache_coverager_get,     NULL)
2602#endif
2603    PHP_FE(xcache_get_special_value, NULL)
2604    PHP_FE(xcache_get_op_type,       NULL)
2605    PHP_FE(xcache_get_data_type,     NULL)
2606    PHP_FE(xcache_get_opcode,        NULL)
2607#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
2608    PHP_FE(xcache_get_opcode_spec,   NULL)
2609#endif
2610    PHP_FE(xcache_is_autoglobal,     NULL)
2611    PHP_FE(xcache_inc,               NULL)
2612    PHP_FE(xcache_dec,               NULL)
2613    PHP_FE(xcache_get,               NULL)
2614    PHP_FE(xcache_set,               NULL)
2615    PHP_FE(xcache_isset,             NULL)
2616    PHP_FE(xcache_unset,             NULL)
2617    {NULL, NULL,                     NULL}
2618};
2619/* }}} */
2620
2621/* old signal handlers {{{ */
2622typedef void (*xc_sighandler_t)(int);
2623#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
2624#include "foreachcoresig.h"
2625#undef FOREACH_SIG
2626/* }}} */
2627static void xcache_signal_handler(int sig);
2628static void xcache_restore_signal_handler() /* {{{ */
2629{
2630#define FOREACH_SIG(sig) do { \
2631    if (old_##sig##_handler != xcache_signal_handler) { \
2632        signal(sig, old_##sig##_handler); \
2633    } \
2634    else { \
2635        signal(sig, SIG_DFL); \
2636    } \
2637} while (0)
2638#include "foreachcoresig.h"
2639#undef FOREACH_SIG
2640}
2641/* }}} */
2642static void xcache_init_signal_handler() /* {{{ */
2643{
2644#define FOREACH_SIG(sig) \
2645    old_##sig##_handler = signal(sig, xcache_signal_handler)
2646#include "foreachcoresig.h"
2647#undef FOREACH_SIG
2648}
2649/* }}} */
2650static void xcache_signal_handler(int sig) /* {{{ */
2651{
2652    xcache_restore_signal_handler();
2653    if (xc_coredump_dir && xc_coredump_dir[0]) {
2654        chdir(xc_coredump_dir);
2655    }
2656    raise(sig);
2657}
2658/* }}} */
2659
2660/* {{{ PHP_INI */
2661
2662static PHP_INI_MH(xc_OnUpdateDummy)
2663{
2664    return SUCCESS;
2665}
2666
2667static PHP_INI_MH(xc_OnUpdateULong)
2668{
2669    zend_ulong *p = (zend_ulong *) mh_arg1;
2670
2671    *p = (zend_ulong) atoi(new_value);
2672    return SUCCESS;
2673}
2674
2675static PHP_INI_MH(xc_OnUpdateBool)
2676{
2677    zend_bool *p = (zend_bool *)mh_arg1;
2678
2679    if (strncasecmp("on", new_value, sizeof("on"))) {
2680        *p = (zend_bool) atoi(new_value);
2681    }
2682    else {
2683        *p = (zend_bool) 1;
2684    }
2685    return SUCCESS;
2686}
2687
2688static PHP_INI_MH(xc_OnUpdateString)
2689{
2690    char **p = (char**)mh_arg1;
2691    if (*p) {
2692        pefree(*p, 1);
2693    }
2694    *p = pemalloc(strlen(new_value) + 1, 1);
2695    strcpy(*p, new_value);
2696    return SUCCESS;
2697}
2698
2699#ifndef ZEND_ENGINE_2
2700#define OnUpdateLong OnUpdateInt
2701#endif
2702
2703#ifdef ZEND_WIN32
2704#   define DEFAULT_PATH "xcache"
2705#else
2706#   define DEFAULT_PATH "/dev/zero"
2707#endif
2708PHP_INI_BEGIN()
2709    PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
2710    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
2711    PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
2712    PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
2713    /* opcode cache */
2714    PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2715    PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2716    PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2717    PHP_INI_ENTRY1     ("xcache.shm_scheme",          "mmap", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_shm_scheme)
2718    PHP_INI_ENTRY1     ("xcache.ttl",                    "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_ttl)
2719    PHP_INI_ENTRY1     ("xcache.gc_interval",            "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_gc_interval)
2720    /* var cache */
2721    PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2722    PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2723    PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2724    PHP_INI_ENTRY1     ("xcache.var_maxttl",             "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_maxttl)
2725    PHP_INI_ENTRY1     ("xcache.var_gc_interval",      "120", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_gc_interval)
2726
2727    STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
2728    STD_PHP_INI_BOOLEAN("xcache.stat",                   "1", PHP_INI_ALL,    OnUpdateBool,        stat,              zend_xcache_globals, xcache_globals)
2729    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
2730#ifdef HAVE_XCACHE_OPTIMIZER
2731    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
2732#endif
2733    STD_PHP_INI_ENTRY  ("xcache.var_ttl",                "0", PHP_INI_ALL,    OnUpdateLong,        var_ttl,           zend_xcache_globals, xcache_globals)
2734#ifdef HAVE_XCACHE_COVERAGER
2735    STD_PHP_INI_BOOLEAN("xcache.coverager"      ,        "0", PHP_INI_ALL,    OnUpdateBool,        coverager,         zend_xcache_globals, xcache_globals)
2736    PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
2737#endif
2738PHP_INI_END()
2739/* }}} */
2740/* {{{ PHP_MINFO_FUNCTION(xcache) */
2741static PHP_MINFO_FUNCTION(xcache)
2742{
2743    char buf[100];
2744    char *ptr;
2745    int left, len;
2746    xc_shm_scheme_t *scheme;
2747    char *covdumpdir;
2748
2749    php_info_print_table_start();
2750    php_info_print_table_header(2, "XCache Support", "enabled");
2751    php_info_print_table_row(2, "Version", XCACHE_VERSION);
2752    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
2753    php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
2754
2755    if (xc_php_size) {
2756        ptr = _php_math_number_format(xc_php_size, 0, '.', ',');
2757        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_php_hcache.size, xc_php_hentry.size);
2758        php_info_print_table_row(2, "Opcode Cache", buf);
2759        efree(ptr);
2760    }
2761    else {
2762        php_info_print_table_row(2, "Opcode Cache", "disabled");
2763    }
2764    if (xc_var_size) {
2765        ptr = _php_math_number_format(xc_var_size, 0, '.', ',');
2766        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_var_hcache.size, xc_var_hentry.size);
2767        php_info_print_table_row(2, "Variable Cache", buf);
2768        efree(ptr);
2769    }
2770    else {
2771        php_info_print_table_row(2, "Variable Cache", "disabled");
2772    }
2773
2774    left = sizeof(buf);
2775    ptr = buf;
2776    buf[0] = '\0';
2777    for (scheme = xc_shm_scheme_first(); scheme; scheme = xc_shm_scheme_next(scheme)) {
2778        len = snprintf(ptr, left, ptr == buf ? "%s" : ", %s", xc_shm_scheme_name(scheme));
2779        left -= len;
2780        ptr += len;
2781    }
2782    php_info_print_table_row(2, "Shared Memory Schemes", buf);
2783
2784#ifdef HAVE_XCACHE_COVERAGER
2785    if (cfg_get_string("xcache.coveragedump_directory", &covdumpdir) != SUCCESS || !covdumpdir[0]) {
2786        covdumpdir = NULL;
2787    }
2788    php_info_print_table_row(2, "Coverage Auto Dumper", XG(coverager) && covdumpdir ? "enabled" : "disabled");
2789#endif
2790    php_info_print_table_end();
2791
2792    DISPLAY_INI_ENTRIES();
2793}
2794/* }}} */
2795/* {{{ extension startup */
2796static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
2797{
2798    zend_extension extension;
2799
2800    extension = *new_extension;
2801    extension.handle = handle;
2802
2803    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
2804
2805    zend_llist_prepend_element(&zend_extensions, &extension);
2806    TRACE("%s", "registered");
2807}
2808
2809static zend_llist_element *xc_llist_get_element_by_zend_extension(zend_llist *l, const char *extension_name)
2810{
2811    zend_llist_element *element;
2812
2813    for (element = zend_extensions.head; element; element = element->next) {
2814        zend_extension *extension = (zend_extension *) element->data;
2815
2816        if (!strcmp(extension->name, extension_name)) {
2817            return element;
2818        }
2819    }
2820    return NULL;
2821}
2822
2823static void xc_llist_prepend(zend_llist *l, zend_llist_element *element)
2824{
2825    element->next = l->head;
2826    element->prev = NULL;
2827    if (l->head) {
2828        l->head->prev = element;
2829    }
2830    else {
2831        l->tail = element;
2832    }
2833    l->head = element;
2834    ++l->count;
2835}
2836
2837static void xc_llist_unlink(zend_llist *l, zend_llist_element *element)
2838{
2839    if ((element)->prev) {
2840        (element)->prev->next = (element)->next;
2841    }
2842    else {
2843        (l)->head = (element)->next;
2844    }
2845
2846    if ((element)->next) {
2847        (element)->next->prev = (element)->prev;
2848    }
2849    else {
2850        (l)->tail = (element)->prev;
2851    }
2852
2853    --l->count;
2854}
2855
2856static int xc_zend_extension_startup(zend_extension *extension)
2857{
2858    if (extension->startup) {
2859        if (extension->startup(extension) != SUCCESS) {
2860            return FAILURE;
2861        }
2862    }
2863    return SUCCESS;
2864}
2865/* }}} */
2866static int xc_ptr_compare_func(void *p1, void *p2) /* {{{ */
2867{
2868    return p1 == p2;
2869}
2870/* }}} */
2871static int xc_zend_remove_extension(zend_extension *extension) /* {{{ */
2872{
2873    llist_dtor_func_t dtor;
2874
2875    assert(extension);
2876    dtor = zend_extensions.dtor; /* avoid dtor */
2877    zend_extensions.dtor = NULL;
2878    zend_llist_del_element(&zend_extensions, extension, xc_ptr_compare_func);
2879    zend_extensions.dtor = dtor;
2880    return SUCCESS;
2881}
2882/* }}} */
2883static int xc_config_hash(xc_hash_t *p, char *name, char *default_value) /* {{{ */
2884{
2885    int bits, size;
2886    char *value;
2887
2888    if (cfg_get_string(name, &value) != SUCCESS) {
2889        value = default_value;
2890    }
2891
2892    p->size = zend_atoi(value, strlen(value));
2893    for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
2894        /* empty body */
2895    }
2896    p->size = size;
2897    p->bits = bits;
2898    p->mask = size - 1;
2899
2900    return SUCCESS;
2901}
2902/* }}} */
2903static int xc_config_long(zend_ulong *p, char *name, char *default_value) /* {{{ */
2904{
2905    char *value;
2906
2907    if (cfg_get_string(name, &value) != SUCCESS) {
2908        value = default_value;
2909    }
2910
2911    *p = zend_atoi(value, strlen(value));
2912    return SUCCESS;
2913}
2914/* }}} */
2915/* {{{ PHP_MINIT_FUNCTION(xcache) */
2916static PHP_MINIT_FUNCTION(xcache)
2917{
2918    char *env;
2919    zend_extension *ext;
2920    zend_llist_position lpos;
2921
2922    xc_module_gotup = 1;
2923    if (!xc_zend_extension_gotup) {
2924        xc_zend_extension_register(&zend_extension_entry, 0);
2925        xc_zend_extension_startup(&zend_extension_entry);
2926        xc_zend_extension_faked = 1;
2927    }
2928
2929    ext = zend_get_extension("Zend Optimizer");
2930    if (ext) {
2931        /* zend_optimizer.optimization_level>0 is not compatible with other cacher, disabling */
2932        ext->op_array_handler = NULL;
2933    }
2934    /* cache if there's an op_array_ctor */
2935    for (ext = zend_llist_get_first_ex(&zend_extensions, &lpos);
2936            ext;
2937            ext = zend_llist_get_next_ex(&zend_extensions, &lpos)) {
2938        if (ext->op_array_ctor) {
2939            xc_have_op_array_ctor = 1;
2940            break;
2941        }
2942    }
2943
2944
2945#ifndef PHP_GINIT
2946    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
2947#endif
2948    REGISTER_INI_ENTRIES();
2949
2950    if (strcmp(sapi_module.name, "cli") == 0) {
2951        if ((env = getenv("XCACHE_TEST")) != NULL) {
2952            zend_alter_ini_entry("xcache.test", sizeof("xcache.test"), env, strlen(env) + 1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP);
2953        }
2954        if (!xc_test) {
2955            /* disable cache for cli except for test */
2956            xc_php_size = xc_var_size = 0;
2957        }
2958    }
2959
2960    xc_config_long(&xc_php_size,       "xcache.size",        "0");
2961    xc_config_hash(&xc_php_hcache,     "xcache.count",       "1");
2962    xc_config_hash(&xc_php_hentry,     "xcache.slots",      "8K");
2963
2964    xc_config_long(&xc_var_size,       "xcache.var_size",    "0");
2965    xc_config_hash(&xc_var_hcache,     "xcache.var_count",   "1");
2966    xc_config_hash(&xc_var_hentry,     "xcache.var_slots",  "8K");
2967
2968    if (xc_php_size <= 0) {
2969        xc_php_size = xc_php_hcache.size = 0;
2970    }
2971    if (xc_var_size <= 0) {
2972        xc_var_size = xc_var_hcache.size = 0;
2973    }
2974
2975    if (xc_coredump_dir && xc_coredump_dir[0]) {
2976        xcache_init_signal_handler();
2977    }
2978
2979    xc_init_constant(module_number TSRMLS_CC);
2980    xc_shm_init_modules();
2981
2982    if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
2983        if (xc_init(module_number TSRMLS_CC) != SUCCESS) {
2984            zend_error(E_ERROR, "XCache: Cannot init");
2985            goto err_init;
2986        }
2987        xc_initized = 1;
2988    }
2989
2990#ifdef HAVE_XCACHE_COVERAGER
2991    xc_coverager_init(module_number TSRMLS_CC);
2992#endif
2993
2994    return SUCCESS;
2995
2996err_init:
2997    return FAILURE;
2998}
2999/* }}} */
3000/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
3001static PHP_MSHUTDOWN_FUNCTION(xcache)
3002{
3003    if (xc_initized) {
3004        xc_destroy();
3005    }
3006    if (xc_mmap_path) {
3007        pefree(xc_mmap_path, 1);
3008        xc_mmap_path = NULL;
3009    }
3010    if (xc_shm_scheme) {
3011        pefree(xc_shm_scheme, 1);
3012        xc_shm_scheme = NULL;
3013    }
3014
3015#ifdef HAVE_XCACHE_COVERAGER
3016    xc_coverager_destroy();
3017#endif
3018
3019    if (xc_coredump_dir && xc_coredump_dir[0]) {
3020        xcache_restore_signal_handler();
3021    }
3022    if (xc_coredump_dir) {
3023        pefree(xc_coredump_dir, 1);
3024        xc_coredump_dir = NULL;
3025    }
3026#ifndef PHP_GINIT
3027#   ifdef ZTS
3028    ts_free_id(xcache_globals_id);
3029#   else
3030    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
3031#   endif
3032#endif
3033
3034    if (xc_zend_extension_faked) {
3035        zend_extension *ext = zend_get_extension(XCACHE_NAME);
3036        if (ext->shutdown) {
3037            ext->shutdown(ext);
3038        }
3039        xc_zend_remove_extension(ext);
3040    }
3041    UNREGISTER_INI_ENTRIES();
3042
3043    xc_module_gotup = 0;
3044    xc_zend_extension_gotup = 0;
3045    xc_zend_extension_faked = 0;
3046
3047    return SUCCESS;
3048}
3049/* }}} */
3050/* {{{ PHP_RINIT_FUNCTION(xcache) */
3051static PHP_RINIT_FUNCTION(xcache)
3052{
3053    xc_request_init(TSRMLS_C);
3054    return SUCCESS;
3055}
3056/* }}} */
3057/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
3058#ifndef ZEND_ENGINE_2
3059static PHP_RSHUTDOWN_FUNCTION(xcache)
3060#else
3061static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
3062#endif
3063{
3064#ifdef ZEND_ENGINE_2
3065    TSRMLS_FETCH();
3066#endif
3067
3068    xc_request_shutdown(TSRMLS_C);
3069    return SUCCESS;
3070}
3071/* }}} */
3072/* {{{ module dependencies */
3073#if ZEND_MODULE_API_NO >= 20050922
3074static const zend_module_dep xcache_module_deps[] = {
3075    ZEND_MOD_REQUIRED("standard")
3076    ZEND_MOD_CONFLICTS("apc")
3077    ZEND_MOD_CONFLICTS("eAccelerator")
3078    ZEND_MOD_CONFLICTS("Turck MMCache")
3079    {NULL, NULL, NULL}
3080};
3081#endif
3082/* }}} */ 
3083/* {{{ module definition structure */
3084
3085zend_module_entry xcache_module_entry = {
3086#if ZEND_MODULE_API_NO >= 20050922
3087    STANDARD_MODULE_HEADER_EX,
3088    NULL,
3089    xcache_module_deps,
3090#else
3091    STANDARD_MODULE_HEADER,
3092#endif
3093    XCACHE_NAME,
3094    xcache_functions,
3095    PHP_MINIT(xcache),
3096    PHP_MSHUTDOWN(xcache),
3097    PHP_RINIT(xcache),
3098#ifndef ZEND_ENGINE_2
3099    PHP_RSHUTDOWN(xcache),
3100#else
3101    NULL,
3102#endif
3103    PHP_MINFO(xcache),
3104    XCACHE_VERSION,
3105#ifdef PHP_GINIT
3106    PHP_MODULE_GLOBALS(xcache),
3107    PHP_GINIT(xcache),
3108    PHP_GSHUTDOWN(xcache),
3109#endif
3110#ifdef ZEND_ENGINE_2
3111    ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
3112#else
3113    NULL,
3114    NULL,
3115#endif
3116    STANDARD_MODULE_PROPERTIES_EX
3117};
3118
3119#ifdef COMPILE_DL_XCACHE
3120ZEND_GET_MODULE(xcache)
3121#endif
3122/* }}} */
3123static startup_func_t xc_last_ext_startup;
3124static int xc_zend_startup_last(zend_extension *extension) /* {{{ */
3125{
3126    /* restore */
3127    extension->startup = xc_last_ext_startup;
3128    if (extension->startup) {
3129        if (extension->startup(extension) != SUCCESS) {
3130            return FAILURE;
3131        }
3132    }
3133    assert(xc_llist_zend_extension);
3134    xc_llist_prepend(&zend_extensions, xc_llist_zend_extension);
3135    if (!xc_module_gotup) {
3136        return zend_startup_module(&xcache_module_entry);
3137    }
3138    return SUCCESS;
3139}
3140/* }}} */
3141ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
3142{
3143    xc_zend_extension_gotup = 1;
3144
3145    if (!origin_compile_file) {
3146        origin_compile_file = zend_compile_file;
3147        zend_compile_file = xc_check_initial_compile_file;
3148    }
3149
3150    if (zend_llist_count(&zend_extensions) > 1) {
3151        zend_llist_position lpos;
3152        zend_extension *ext;
3153
3154        xc_llist_zend_extension = xc_llist_get_element_by_zend_extension(&zend_extensions, XCACHE_NAME);
3155        xc_llist_unlink(&zend_extensions, xc_llist_zend_extension);
3156
3157        ext = (zend_extension *) zend_llist_get_last_ex(&zend_extensions, &lpos);
3158        assert(ext && ext != xc_llist_zend_extension);
3159        xc_last_ext_startup = ext->startup;
3160        ext->startup = xc_zend_startup_last;
3161    }
3162    else if (!xc_module_gotup) {
3163        return zend_startup_module(&xcache_module_entry);
3164    }
3165    return SUCCESS;
3166}
3167/* }}} */
3168ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
3169{
3170    /* empty */
3171}
3172/* }}} */
3173ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
3174{
3175#ifdef HAVE_XCACHE_COVERAGER
3176    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
3177#endif
3178}
3179/* }}} */
3180ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
3181{
3182#if 0
3183    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
3184#endif
3185}
3186/* }}} */
3187ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
3188{
3189#if 0
3190    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
3191#endif
3192}
3193/* }}} */
3194/* {{{ zend extension definition structure */
3195ZEND_DLEXPORT zend_extension zend_extension_entry = {
3196    XCACHE_NAME,
3197    XCACHE_VERSION,
3198    XCACHE_AUTHOR,
3199    XCACHE_URL,
3200    XCACHE_COPYRIGHT,
3201    xcache_zend_startup,
3202    xcache_zend_shutdown,
3203    NULL,           /* activate_func_t */
3204    NULL,           /* deactivate_func_t */
3205    NULL,           /* message_handler_func_t */
3206#ifdef HAVE_XCACHE_OPTIMIZER
3207    xc_optimizer_op_array_handler,
3208#else
3209    NULL,           /* op_array_handler_func_t */
3210#endif
3211    xcache_statement_handler,
3212    xcache_fcall_begin_handler,
3213    xcache_fcall_end_handler,
3214    NULL,           /* op_array_ctor_func_t */
3215    NULL,           /* op_array_dtor_func_t */
3216    STANDARD_ZEND_EXTENSION_PROPERTIES
3217};
3218
3219#ifndef ZEND_EXT_API
3220#   define ZEND_EXT_API ZEND_DLEXPORT
3221#endif
3222#if COMPILE_DL_XCACHE
3223ZEND_EXTENSION();
3224#endif
3225/* }}} */
Note: See TracBrowser for help on using the repository browser.