source: trunk/xcache.c @ 848

Last change on this file since 848 was 848, checked in by moo, 2 years ago

fix md5 digest

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