source: trunk/xcache.c @ 917

Last change on this file since 917 was 917, checked in by moo, 22 months ago

kill sign/const warning

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