source: trunk/xcache.c @ 915

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

code clean up

  • Property svn:eol-style set to native
File size: 115.1 KB
Line 
1
2#if 0
3#define XCACHE_DEBUG
4#endif
5
6#if 0
7#define SHOW_DPRINT
8#endif
9
10/* {{{ macros */
11#include <stdlib.h>
12#include <stdio.h>
13#include <string.h>
14
15#include <signal.h>
16
17#include "php.h"
18#include "ext/standard/info.h"
19#include "ext/standard/md5.h"
20#include "ext/standard/php_math.h"
21#include "ext/standard/php_string.h"
22#include "zend_extensions.h"
23#include "SAPI.h"
24
25#include "xcache.h"
26#ifdef ZEND_ENGINE_2_1
27#include "ext/date/php_date.h"
28#endif
29#include "optimizer.h"
30#include "coverager.h"
31#include "disassembler.h"
32#include "align.h"
33#include "stack.h"
34#include "xcache_globals.h"
35#include "processor.h"
36#include "const_string.h"
37#include "opcode_spec.h"
38#include "utils.h"
39
40#define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > (pentry)->ctime + (pentry)->ttl)
41#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
42#define LOCK(x) xc_lock((x)->lck)
43#define UNLOCK(x) xc_unlock((x)->lck)
44
45#define ENTER_LOCK_EX(x) \
46    xc_lock((x)->lck); \
47    zend_try { \
48        do
49#define LEAVE_LOCK_EX(x) \
50        while (0); \
51    } zend_catch { \
52        catched = 1; \
53    } zend_end_try(); \
54    xc_unlock((x)->lck)
55
56#define ENTER_LOCK(x) do { \
57    int catched = 0; \
58    ENTER_LOCK_EX(x)
59#define LEAVE_LOCK(x) \
60    LEAVE_LOCK_EX(x); \
61    if (catched) { \
62        zend_bailout(); \
63    } \
64} while(0)
65
66/* }}} */
67
68/* {{{ globals */
69static char *xc_shm_scheme = NULL;
70static char *xc_mmap_path = NULL;
71static char *xc_coredump_dir = NULL;
72
73static xc_hash_t xc_php_hcache = { 0 };
74static xc_hash_t xc_php_hentry = { 0 };
75static xc_hash_t xc_var_hcache = { 0 };
76static xc_hash_t xc_var_hentry = { 0 };
77
78static zend_ulong xc_php_ttl    = 0;
79static zend_ulong xc_var_maxttl = 0;
80
81enum { xc_deletes_gc_interval = 120 };
82static zend_ulong xc_php_gc_interval = 0;
83static zend_ulong xc_var_gc_interval = 0;
84
85/* total size */
86static zend_ulong xc_php_size  = 0;
87static zend_ulong xc_var_size  = 0;
88
89static xc_cache_t **xc_php_caches = NULL;
90static xc_cache_t **xc_var_caches = NULL;
91
92static zend_bool xc_initized = 0;
93static time_t xc_init_time = 0;
94static long unsigned xc_init_instance_id = 0;
95#ifdef ZTS
96static long unsigned xc_init_instance_subid = 0;
97#endif
98static zend_compile_file_t *origin_compile_file = NULL;
99static zend_compile_file_t *old_compile_file = NULL;
100static zend_llist_element  *xc_llist_zend_extension = NULL;
101
102static zend_bool xc_test = 0;
103static zend_bool xc_readonly_protection = 0;
104
105zend_bool xc_have_op_array_ctor = 0;
106
107static zend_bool xc_module_gotup = 0;
108static zend_bool xc_zend_extension_gotup = 0;
109static zend_bool xc_zend_extension_faked = 0;
110#if !COMPILE_DL_XCACHE
111#   define zend_extension_entry xcache_zend_extension_entry
112#endif
113ZEND_DLEXPORT zend_extension zend_extension_entry;
114ZEND_DECLARE_MODULE_GLOBALS(xcache);
115
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 + 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 >= gc_interval) {
484        ENTER_LOCK(cache) {
485            if (XG(request_time) - cache->last_gc_expires >= 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(ZEND_24(NOTHING, (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    int i, class_len;
1243    xc_cest_t cest;
1244    xc_entry_data_php_t *php = (xc_entry_data_php_t *) data;
1245
1246    class_name = Z_OP_CONSTANT(opline->op1).value.str.val;
1247    class_len  = Z_OP_CONSTANT(opline->op1).value.str.len;
1248    if (zend_hash_find(CG(class_table), class_name, class_len, (void **) &cest) == FAILURE) {
1249        assert(0);
1250    }
1251    TRACE("got ZEND_DECLARE_INHERITED_CLASS: %s", class_name + 1);
1252    /* let's see which class */
1253    for (i = 0; i < php->classinfo_cnt; i ++) {
1254        if (memcmp(ZSTR_S(php->classinfos[i].key), class_name, class_len) == 0) {
1255            php->classinfos[i].oplineno = oplineno;
1256            php->have_early_binding = 1;
1257            break;
1258        }
1259    }
1260
1261    if (i == php->classinfo_cnt) {
1262        assert(0);
1263    }
1264}
1265/* }}} */
1266#endif
1267
1268/* {{{ Constant Usage */
1269#ifdef ZEND_ENGINE_2_4
1270#   define xcache_literal_is_dir  1
1271#   define xcache_literal_is_file 2
1272#else
1273#   define xcache_op1_is_file 1
1274#   define xcache_op1_is_dir  2
1275#   define xcache_op2_is_file 4
1276#   define xcache_op2_is_dir  8
1277#endif
1278typedef struct {
1279    zend_bool filepath_used;
1280    zend_bool dirpath_used;
1281    zend_bool ufilepath_used;
1282    zend_bool udirpath_used;
1283} xc_const_usage_t;
1284/* }}} */
1285static 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) /* {{{ */
1286{
1287    int i;
1288    xc_vector_t details;
1289
1290    xc_vector_init(xc_op_array_info_detail_t, &details);
1291
1292#define XCACHE_ANALYZE_LITERAL(type) \
1293    if (zend_binary_strcmp(Z_STRVAL(literal->constant), Z_STRLEN(literal->constant), compiler->new_entry.type##path, compiler->new_entry.type##path_len) == 0) { \
1294        usage->type##path_used = 1; \
1295        literalinfo |= xcache_##literal##_is_##type; \
1296    }
1297
1298#define XCACHE_U_ANALYZE_LITERAL(type) \
1299    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) { \
1300        usage->u##type##path_used = 1; \
1301        literalinfo |= xcache_##literal##_is_##type; \
1302    }
1303
1304#define XCACHE_ANALYZE_OP(type, op) \
1305    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) { \
1306        usage->type##path_used = 1; \
1307        oplineinfo |= xcache_##op##_is_##type; \
1308    }
1309
1310#define XCACHE_U_ANALYZE_OP(type, op) \
1311    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) { \
1312        usage->u##type##path_used = 1; \
1313        oplineinfo |= xcache_##op##_is_##type; \
1314    }
1315
1316#ifdef ZEND_ENGINE_2_4
1317    for (i = 0; i < op_array->last_literal; i++) {
1318        zend_literal *literal = &op_array->literals[i];
1319        zend_uint literalinfo = 0;
1320        if (Z_TYPE(literal->constant) == IS_STRING) {
1321            XCACHE_ANALYZE_LITERAL(file)
1322            else XCACHE_ANALYZE_LITERAL(dir)
1323        }
1324#ifdef IS_UNICODE
1325        else if (Z_TYPE(literal->constant) == IS_UNICODE) {
1326            XCACHE_U_ANALYZE_LITERAL(file)
1327            else XCACHE_U_ANALYZE_LITERAL(dir)
1328        }
1329#endif
1330        if (literalinfo) {
1331            xc_op_array_info_detail_t detail;
1332            detail.index = i;
1333            detail.info  = literalinfo;
1334            xc_vector_add(xc_op_array_info_detail_t, &details, detail);
1335        }
1336    }
1337
1338    op_array_info->literalinfo_cnt = details.cnt;
1339    op_array_info->literalinfos    = xc_vector_detach(xc_op_array_info_detail_t, &details);
1340#else /* ZEND_ENGINE_2_4 */
1341    for (i = 0; i < op_array->last; i++) {
1342        zend_op *opline = &op_array->opcodes[i];
1343        zend_uint oplineinfo = 0;
1344        if (Z_OP_TYPE(opline->op1) == IS_CONST) {
1345            if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) {
1346                XCACHE_ANALYZE_OP(file, op1)
1347                else XCACHE_ANALYZE_OP(dir, op1)
1348            }
1349#ifdef IS_UNICODE
1350            else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) {
1351                XCACHE_U_ANALYZE_OP(file, op1)
1352                else XCACHE_U_ANALYZE_OP(dir, op1)
1353            }
1354#endif
1355        }
1356
1357        if (Z_OP_TYPE(opline->op2) == IS_CONST) {
1358            if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) {
1359                XCACHE_ANALYZE_OP(file, op2)
1360                else XCACHE_ANALYZE_OP(dir, op2)
1361            }
1362#ifdef IS_UNICODE
1363            else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) {
1364                XCACHE_U_ANALYZE_OP(file, op2)
1365                else XCACHE_U_ANALYZE_OP(dir, op2)
1366            }
1367#endif
1368        }
1369
1370        if (oplineinfo) {
1371            xc_op_array_info_detail_t detail;
1372            detail.index = i;
1373            detail.info  = oplineinfo;
1374            xc_vector_add(xc_op_array_info_detail_t, &details, detail);
1375        }
1376    }
1377
1378    op_array_info->oplineinfo_cnt = details.cnt;
1379    op_array_info->oplineinfos    = xc_vector_detach(xc_op_array_info_detail_t, &details);
1380#endif /* ZEND_ENGINE_2_4 */
1381    xc_vector_free(xc_op_array_info_detail_t, &details);
1382}
1383/* }}} */
1384void 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) /* {{{ */
1385{
1386    int i;
1387
1388#ifdef ZEND_ENGINE_2_4
1389    for (i = 0; i < op_array_info->literalinfo_cnt; ++i) {
1390        int index = op_array_info->literalinfos[i].index;
1391        int literalinfo = op_array_info->literalinfos[i].info;
1392        zend_literal *literal = &op_array->literals[index];
1393        if ((literalinfo & xcache_literal_is_file)) {
1394            if (!shallow_copy) {
1395                efree(Z_STRVAL(literal->constant));
1396            }
1397            if (Z_TYPE(literal->constant) == IS_STRING) {
1398                assert(entry_php->filepath);
1399                ZVAL_STRINGL(&literal->constant, entry_php->filepath, entry_php->filepath_len, !shallow_copy);
1400                TRACE("restored literal constant: %s", entry_php->filepath);
1401            }
1402#ifdef IS_UNICODE
1403            else if (Z_TYPE(literal->constant) == IS_UNICODE) {
1404                assert(entry_php->ufilepath);
1405                ZVAL_UNICODEL(&literal->constant, entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy);
1406            }
1407#endif
1408            else {
1409                assert(0);
1410            }
1411        }
1412        else if ((literalinfo & xcache_literal_is_dir)) {
1413            if (!shallow_copy) {
1414                efree(Z_STRVAL(literal->constant));
1415            }
1416            if (Z_TYPE(literal->constant) == IS_STRING) {
1417                assert(entry_php->dirpath);
1418                TRACE("restored literal constant: %s", entry_php->dirpath);
1419                ZVAL_STRINGL(&literal->constant, entry_php->dirpath, entry_php->dirpath_len, !shallow_copy);
1420            }
1421#ifdef IS_UNICODE
1422            else if (Z_TYPE(literal->constant) == IS_UNICODE) {
1423                assert(!entry_php->udirpath);
1424                ZVAL_UNICODEL(&literal->constant, entry_php->udirpath, entry_php->udirpath_len, !shallow_copy);
1425            }
1426#endif
1427            else {
1428                assert(0);
1429            }
1430        }
1431    }
1432#else
1433    for (i = 0; i < op_array_info->oplineinfo_cnt; ++i) {
1434        int oplineno = op_array_info->oplineinfos[i].index;
1435        int oplineinfo = op_array_info->oplineinfos[i].info;
1436        zend_op *opline = &op_array->opcodes[oplineno];
1437        if ((oplineinfo & xcache_op1_is_file)) {
1438            assert(Z_OP_TYPE(opline->op1) == IS_CONST);
1439            if (!shallow_copy) {
1440                efree(Z_STRVAL(Z_OP_CONSTANT(opline->op1)));
1441            }
1442            if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) {
1443                assert(entry_php->filepath);
1444                ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op1), entry_php->filepath, entry_php->filepath_len, !shallow_copy);
1445                TRACE("restored op1 constant: %s", entry_php->filepath);
1446            }
1447#ifdef IS_UNICODE
1448            else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) {
1449                assert(entry_php->ufilepath);
1450                ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op1), entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy);
1451            }
1452#endif
1453            else {
1454                assert(0);
1455            }
1456        }
1457        else if ((oplineinfo & xcache_op1_is_dir)) {
1458            assert(Z_OP_TYPE(opline->op1) == IS_CONST);
1459            if (!shallow_copy) {
1460                efree(Z_STRVAL(Z_OP_CONSTANT(opline->op1)));
1461            }
1462            if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) {
1463                assert(entry_php->dirpath);
1464                TRACE("restored op1 constant: %s", entry_php->dirpath);
1465                ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op1), entry_php->dirpath, entry_php->dirpath_len, !shallow_copy);
1466            }
1467#ifdef IS_UNICODE
1468            else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) {
1469                assert(!entry_php->udirpath);
1470                ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op1), entry_php->udirpath, entry_php->udirpath_len, !shallow_copy);
1471            }
1472#endif
1473            else {
1474                assert(0);
1475            }
1476        }
1477
1478        if ((oplineinfo & xcache_op2_is_file)) {
1479            assert(Z_OP_TYPE(opline->op2) == IS_CONST);
1480            if (!shallow_copy) {
1481                efree(Z_STRVAL(Z_OP_CONSTANT(opline->op2)));
1482            }
1483            if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) {
1484                assert(entry_php->filepath);
1485                TRACE("restored op2 constant: %s", entry_php->filepath);
1486                ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op2), entry_php->filepath, entry_php->filepath_len, !shallow_copy);
1487            }
1488#ifdef IS_UNICODE
1489            else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) {
1490                assert(entry_php->ufilepath);
1491                ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op2), entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy);
1492            }
1493#endif
1494            else {
1495                assert(0);
1496            }
1497        }
1498        else if ((oplineinfo & xcache_op2_is_dir)) {
1499            assert(Z_OP_TYPE(opline->op2) == IS_CONST);
1500            if (!shallow_copy) {
1501                efree(Z_STRVAL(Z_OP_CONSTANT(opline->op2)));
1502            }
1503            if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) {
1504                assert(!entry_php->dirpath);
1505                TRACE("restored op2 constant: %s", entry_php->dirpath);
1506                ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op2), entry_php->dirpath, entry_php->dirpath_len, !shallow_copy);
1507            }
1508#ifdef IS_UNICODE
1509            else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) {
1510                assert(!entry_php->udirpath);
1511                ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op2), entry_php->udirpath, entry_php->udirpath_len, !shallow_copy);
1512            }
1513#endif
1514            else {
1515                assert(0);
1516            }
1517        }
1518    }
1519#endif
1520}
1521/* }}} */
1522static void xc_free_op_array_info(xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */
1523{
1524#ifdef ZEND_ENGINE_2_4
1525    if (op_array_info->literalinfos) {
1526        efree(op_array_info->literalinfos);
1527    }
1528#else
1529    if (op_array_info->oplineinfos) {
1530        efree(op_array_info->oplineinfos);
1531    }
1532#endif
1533}
1534/* }}} */
1535static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */
1536{
1537    int i;
1538    if (php->classinfos) {
1539        for (i = 0; i < php->classinfo_cnt; i ++) {
1540            xc_classinfo_t *classinfo = &php->classinfos[i];
1541            int j;
1542            for (j = 0; j < classinfo->methodinfo_cnt; j ++) {
1543                xc_free_op_array_info(&classinfo->methodinfos[j] TSRMLS_CC);
1544            }
1545
1546            if (classinfo->methodinfos) {
1547                efree(classinfo->methodinfos);
1548            }
1549        }
1550    }
1551    if (php->funcinfos) {
1552        for (i = 0; i < php->funcinfo_cnt; i ++) {
1553            xc_free_op_array_info(&php->funcinfos[i].op_array_info TSRMLS_CC);
1554        }
1555    }
1556    xc_free_op_array_info(&php->op_array_info TSRMLS_CC);
1557
1558#define X_FREE(var) do {\
1559    if (php->var) { \
1560        efree(php->var); \
1561    } \
1562} while (0)
1563
1564#ifdef ZEND_ENGINE_2_1
1565    X_FREE(autoglobals);
1566#endif
1567    X_FREE(classinfos);
1568    X_FREE(funcinfos);
1569#ifdef HAVE_XCACHE_CONSTANT
1570    X_FREE(constinfos);
1571#endif
1572#undef X_FREE
1573}
1574/* }}} */
1575static zend_op_array *xc_compile_php(xc_compiler_t *compiler, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
1576{
1577    zend_op_array *op_array;
1578    int old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt;
1579    zend_bool catched = 0;
1580
1581    /* {{{ compile */
1582    TRACE("compiling %s", h->opened_path ? h->opened_path : h->filename);
1583
1584    old_classinfo_cnt = zend_hash_num_elements(CG(class_table));
1585    old_funcinfo_cnt  = zend_hash_num_elements(CG(function_table));
1586    old_constinfo_cnt = zend_hash_num_elements(EG(zend_constants));
1587
1588    compiler->new_php.op_array = NULL;
1589    XG(initial_compile_file_called) = 0;
1590    zend_try {
1591        op_array = old_compile_file(h, type TSRMLS_CC);
1592    } zend_catch {
1593        catched = 1;
1594    } zend_end_try();
1595
1596    if (catched) {
1597        goto err_bailout;
1598    }
1599
1600    if (op_array == NULL) {
1601        goto err_op_array;
1602    }
1603
1604    if (!XG(initial_compile_file_called)) {
1605        return op_array;
1606    }
1607
1608    /* }}} */
1609    /* {{{ prepare */
1610    zend_restore_compiled_filename(h->opened_path ? h->opened_path : (char *) h->filename TSRMLS_CC);
1611    compiler->new_php.op_array = op_array;
1612
1613#ifdef HAVE_XCACHE_CONSTANT
1614    compiler->new_php.constinfo_cnt  = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt;
1615#endif
1616    compiler->new_php.funcinfo_cnt   = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt;
1617    compiler->new_php.classinfo_cnt  = zend_hash_num_elements(CG(class_table))    - old_classinfo_cnt;
1618#ifdef ZEND_ENGINE_2_1
1619    /* {{{ count new_php.autoglobal_cnt */ {
1620        Bucket *b;
1621
1622        compiler->new_php.autoglobal_cnt = 0;
1623        for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
1624            zend_auto_global *auto_global = (zend_auto_global *) b->pData;
1625            /* check if actived */
1626            if (auto_global->auto_global_callback && !auto_global->armed) {
1627                compiler->new_php.autoglobal_cnt ++;
1628            }
1629        }
1630    }
1631    /* }}} */
1632#endif
1633
1634#define X_ALLOC_N(var, cnt) do {     \
1635    if (compiler->new_php.cnt) {                  \
1636        ECALLOC_N(compiler->new_php.var, compiler->new_php.cnt); \
1637        if (!compiler->new_php.var) {             \
1638            goto err_alloc;          \
1639        }                            \
1640    }                                \
1641    else {                           \
1642        compiler->new_php.var = NULL;             \
1643    }                                \
1644} while (0)
1645
1646#ifdef HAVE_XCACHE_CONSTANT
1647    X_ALLOC_N(constinfos,  constinfo_cnt);
1648#endif
1649    X_ALLOC_N(funcinfos,   funcinfo_cnt);
1650    X_ALLOC_N(classinfos,  classinfo_cnt);
1651#ifdef ZEND_ENGINE_2_1
1652    X_ALLOC_N(autoglobals, autoglobal_cnt);
1653#endif
1654#undef X_ALLOC
1655    /* }}} */
1656
1657    /* {{{ shallow copy, pointers only */ {
1658        Bucket *b;
1659        unsigned int i;
1660        unsigned int j;
1661
1662#define COPY_H(vartype, var, cnt, name, datatype) do {        \
1663    for (i = 0, j = 0; b; i ++, b = b->pListNext) {           \
1664        vartype *data = &compiler->new_php.var[j];                         \
1665                                                              \
1666        if (i < old_##cnt) {                                  \
1667            continue;                                         \
1668        }                                                     \
1669        j ++;                                                 \
1670                                                              \
1671        assert(i < old_##cnt + compiler->new_php.cnt);                     \
1672        assert(b->pData);                                     \
1673        memcpy(&data->name, b->pData, sizeof(datatype));      \
1674        UNISW(NOTHING, data->type = b->key.type;)             \
1675        if (UNISW(1, b->key.type == IS_STRING)) {             \
1676            ZSTR_S(data->key)      = BUCKET_KEY_S(b);         \
1677        }                                                     \
1678        else {                                                \
1679            ZSTR_U(data->key)      = BUCKET_KEY_U(b);         \
1680        }                                                     \
1681        data->key_size   = b->nKeyLength;                     \
1682        data->h          = b->h;                              \
1683    }                                                         \
1684} while(0)
1685
1686#ifdef HAVE_XCACHE_CONSTANT
1687        b = EG(zend_constants)->pListHead; COPY_H(xc_constinfo_t, constinfos, constinfo_cnt, constant, zend_constant);
1688#endif
1689        b = CG(function_table)->pListHead; COPY_H(xc_funcinfo_t,  funcinfos,  funcinfo_cnt,  func,     zend_function);
1690        b = CG(class_table)->pListHead;    COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest,     xc_cest_t);
1691
1692#undef COPY_H
1693
1694        /* for ZE1, cest need to be fixed inside store */
1695
1696#ifdef ZEND_ENGINE_2_1
1697        /* scan for acatived auto globals */
1698        i = 0;
1699        for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) {
1700            zend_auto_global *auto_global = (zend_auto_global *) b->pData;
1701            /* check if actived */
1702            if (auto_global->auto_global_callback && !auto_global->armed) {
1703                xc_autoglobal_t *data = &compiler->new_php.autoglobals[i];
1704
1705                assert(i < compiler->new_php.autoglobal_cnt);
1706                i ++;
1707                UNISW(NOTHING, data->type = b->key.type;)
1708                if (UNISW(1, b->key.type == IS_STRING)) {
1709                    ZSTR_S(data->key)     = BUCKET_KEY_S(b);
1710                }
1711                else {
1712                    ZSTR_U(data->key)     = BUCKET_KEY_U(b);
1713                }
1714                data->key_len = b->nKeyLength - 1;
1715                data->h       = b->h;
1716            }
1717        }
1718#endif
1719    }
1720    /* }}} */
1721
1722    /* {{{ collect info for file/dir path */ {
1723        Bucket *b;
1724        xc_const_usage_t const_usage;
1725        unsigned int i;
1726
1727        xc_entry_php_init(&compiler->new_entry, zend_get_compiled_filename(TSRMLS_C) TSRMLS_CC);
1728        memset(&const_usage, 0, sizeof(const_usage));
1729
1730        for (i = 0; i < compiler->new_php.classinfo_cnt; i ++) {
1731            xc_classinfo_t *classinfo = &compiler->new_php.classinfos[i];
1732            zend_class_entry *ce = CestToCePtr(classinfo->cest);
1733            classinfo->methodinfo_cnt = ce->function_table.nTableSize;
1734            if (classinfo->methodinfo_cnt) {
1735                int j;
1736
1737                ECALLOC_N(classinfo->methodinfos, classinfo->methodinfo_cnt);
1738                if (!classinfo->methodinfos) {
1739                    goto err_alloc;
1740                }
1741
1742                for (j = 0, b = ce->function_table.pListHead; b; j ++, b = b->pListNext) {
1743                    xc_collect_op_array_info(compiler, &const_usage, &classinfo->methodinfos[j], (zend_op_array *) b->pData TSRMLS_CC);
1744                }
1745            }
1746            else {
1747                classinfo->methodinfos = NULL;
1748            }
1749        }
1750
1751        for (i = 0; i < compiler->new_php.funcinfo_cnt; i ++) {
1752            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);
1753        }
1754
1755        xc_collect_op_array_info(compiler, &const_usage, &compiler->new_php.op_array_info, compiler->new_php.op_array TSRMLS_CC);
1756
1757        /* file/dir path free unused */
1758#define X_FREE_UNUSED(var) \
1759        if (!const_usage.var##path_used) { \
1760            efree(compiler->new_entry.var##path); \
1761            compiler->new_entry.var##path = NULL; \
1762            compiler->new_entry.var##path_len = 0; \
1763        }
1764        /* filepath is required to restore op_array->filename, so no free filepath here */
1765        X_FREE_UNUSED(dir)
1766#ifdef IS_UNICODE
1767        X_FREE_UNUSED(ufile)
1768        X_FREE_UNUSED(udir)
1769#endif
1770#undef X_FREE_UNUSED
1771    }
1772    /* }}} */
1773#ifdef XCACHE_ERROR_CACHING
1774    compiler->new_php.compilererrors = ((xc_sandbox_t *) XG(sandbox))->compilererrors;
1775    compiler->new_php.compilererror_cnt = ((xc_sandbox_t *) XG(sandbox))->compilererror_cnt;
1776#endif
1777#ifndef ZEND_COMPILE_DELAYED_BINDING
1778    /* {{{ find inherited classes that should be early-binding */
1779    compiler->new_php.have_early_binding = 0;
1780    {
1781        int i;
1782        for (i = 0; i < compiler->new_php.classinfo_cnt; i ++) {
1783            compiler->new_php.classinfos[i].oplineno = -1;
1784        }
1785    }
1786
1787    xc_undo_pass_two(compiler->new_php.op_array TSRMLS_CC);
1788    xc_foreach_early_binding_class(compiler->new_php.op_array, xc_cache_early_binding_class_cb, (void *) &compiler->new_php TSRMLS_CC);
1789    xc_redo_pass_two(compiler->new_php.op_array TSRMLS_CC);
1790    /* }}} */
1791#endif
1792
1793    return op_array;
1794
1795err_alloc:
1796    xc_free_php(&compiler->new_php TSRMLS_CC);
1797
1798err_bailout:
1799err_op_array:
1800
1801    if (catched) {
1802        zend_bailout();
1803    }
1804
1805    return op_array;
1806}
1807/* }}} */
1808static 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) /* {{{ */
1809{
1810    zend_op_array *op_array;
1811    xc_entry_php_t restored_entry;
1812    xc_entry_data_php_t restored_php;
1813    zend_bool catched;
1814
1815    CG(in_compilation)    = 1;
1816    CG(compiled_filename) = stored_entry->entry.name.str.val;
1817    CG(zend_lineno)       = 0;
1818    TRACE("restoring %d:%s", stored_entry->file_inode, stored_entry->entry.name.str.val);
1819    xc_processor_restore_xc_entry_php_t(&restored_entry, stored_entry TSRMLS_CC);
1820    xc_processor_restore_xc_entry_data_php_t(stored_entry, &restored_php, stored_php, xc_readonly_protection TSRMLS_CC);
1821    restored_entry.php = &restored_php;
1822#ifdef SHOW_DPRINT
1823    xc_dprint(&restored_entry, 0 TSRMLS_CC);
1824#endif
1825
1826    catched = 0;
1827    zend_try {
1828        op_array = xc_entry_install(&restored_entry, h TSRMLS_CC);
1829    } zend_catch {
1830        catched = 1;
1831    } zend_end_try();
1832
1833#ifdef HAVE_XCACHE_CONSTANT
1834    if (restored_php.constinfos) {
1835        efree(restored_php.constinfos);
1836    }
1837#endif
1838    if (restored_php.funcinfos) {
1839        efree(restored_php.funcinfos);
1840    }
1841    if (restored_php.classinfos) {
1842        efree(restored_php.classinfos);
1843    }
1844
1845    if (catched) {
1846        zend_bailout();
1847    }
1848    CG(in_compilation)    = 0;
1849    CG(compiled_filename) = NULL;
1850    TRACE("restored %d:%s", stored_entry->file_inode, stored_entry->entry.name.str.val);
1851    return op_array;
1852}
1853/* }}} */
1854static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
1855{
1856    XG(initial_compile_file_called) = 1;
1857    return origin_compile_file(h, type TSRMLS_CC);
1858}
1859/* }}} */
1860static zend_op_array *xc_compile_file_ex(xc_compiler_t *compiler, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
1861{
1862    /*
1863    if (clog) {
1864        return old;
1865    }
1866
1867    if (cached_entry = getby entry_hash) {
1868        php = cached_entry.php;
1869        php = restore(php);
1870        return php;
1871    }
1872    else {
1873        if (!(php = getby md5)) {
1874            if (clog) {
1875                return old;
1876            }
1877            php = compile();
1878            entry = create entries[entry];
1879        }
1880
1881        entry.php = php;
1882        return php;
1883    }
1884    */
1885
1886    zend_op_array *op_array;
1887    xc_entry_php_t *stored_entry;
1888    xc_entry_data_php_t *stored_php;
1889    zend_bool gaveup = 0;
1890    zend_bool catched = 0;
1891    xc_sandbox_t sandbox;
1892    xc_cache_t *cache = xc_php_caches[compiler->entry_hash.cacheid];
1893
1894    /* stale clogs precheck */
1895    if (XG(request_time) - cache->compiling < 30) {
1896        cache->clogs ++;
1897        return old_compile_file(h, type TSRMLS_CC);
1898    }
1899
1900    /* {{{ entry_lookup/hit/md5_init/php_lookup */
1901    stored_entry = NULL;
1902    stored_php = NULL;
1903
1904    ENTER_LOCK_EX(cache) {
1905        if (!compiler->opened_path && xc_entry_find_include_path_unlocked(compiler, compiler->filename, &stored_entry TSRMLS_CC) == SUCCESS) {
1906            compiler->opened_path = compiler->new_entry.entry.name.str.val;
1907        }
1908        else {
1909            if (!compiler->opened_path && xc_entry_php_resolve_opened_path(compiler, NULL TSRMLS_CC) != SUCCESS) {
1910                gaveup = 1;
1911                break;
1912            }
1913
1914            /* finalize name */
1915            compiler->new_entry.entry.name.str.val = (char *) compiler->opened_path;
1916            compiler->new_entry.entry.name.str.len = strlen(compiler->new_entry.entry.name.str.val);
1917
1918            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);
1919        }
1920
1921        if (stored_entry) {
1922            xc_cache_hit_unlocked(cache TSRMLS_CC);
1923
1924            TRACE(" hit %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val);
1925            xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC);
1926            stored_php = stored_entry->php;
1927            break;
1928        }
1929
1930        cache->misses ++;
1931        TRACE("miss entry %d:%s", compiler->new_entry.file_inode, compiler->new_entry.entry.name.str.val);
1932
1933        if (xc_entry_data_php_init_md5(cache, compiler TSRMLS_CC) != SUCCESS) {
1934            gaveup = 1;
1935            break;
1936        }
1937
1938        stored_php = xc_php_find_unlocked(cache, &compiler->new_php TSRMLS_CC);
1939
1940        if (stored_php) {
1941            compiler->new_entry.php = stored_php;
1942            xc_entry_php_init(&compiler->new_entry, compiler->opened_path TSRMLS_CC);
1943            stored_entry = xc_entry_php_store_unlocked(cache, compiler->entry_hash.entryslotid, &compiler->new_entry TSRMLS_CC);
1944            if (stored_entry) {
1945                xc_php_addref_unlocked(stored_php);
1946                TRACE(" cached %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val);
1947                xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC);
1948            }
1949            else {
1950                gaveup = 1;
1951            }
1952            break;
1953        }
1954
1955        if (XG(request_time) - cache->compiling < 30) {
1956            TRACE("%s", "miss php, but compiling");
1957            cache->clogs ++;
1958            gaveup = 1;
1959            break;
1960        }
1961
1962        TRACE("%s", "miss php, going to compile");
1963        cache->compiling = XG(request_time);
1964    } LEAVE_LOCK_EX(cache);
1965
1966    if (catched) {
1967        cache->compiling = 0;
1968        zend_bailout();
1969    }
1970
1971    /* found entry */
1972    if (stored_entry && stored_php) {
1973        return xc_compile_restore(stored_entry, stored_php, h TSRMLS_CC);
1974    }
1975
1976    /* gaveup */
1977    if (gaveup) {
1978        return old_compile_file(h, type TSRMLS_CC);
1979    }
1980    /* }}} */
1981
1982    op_array = NULL;
1983    /* {{{ compile */
1984    /* make compile inside sandbox */
1985    xc_sandbox_init(&sandbox, h->opened_path ? h->opened_path : h->filename TSRMLS_CC);
1986
1987#ifdef HAVE_XCACHE_CONSTANT
1988    compiler->new_php.constinfos  = NULL;
1989#endif
1990    compiler->new_php.funcinfos   = NULL;
1991    compiler->new_php.classinfos  = NULL;
1992#ifdef ZEND_ENGINE_2_1
1993    compiler->new_php.autoglobals = NULL;
1994#endif
1995    memset(&compiler->new_php.op_array_info, 0, sizeof(compiler->new_php.op_array_info));
1996
1997    zend_try {
1998        op_array = xc_compile_php(compiler, h, type TSRMLS_CC);
1999    } zend_catch {
2000        catched = 1;
2001    } zend_end_try();
2002
2003    if (catched || !op_array) {
2004        goto err_aftersandbox;
2005    }
2006
2007    /* not cachable */
2008    if (!compiler->new_php.op_array) {
2009        cache->compiling = 0;
2010        /* it's not cachable, but don't scare the users with high misses */
2011        cache->misses --;
2012        xc_sandbox_free(&sandbox, XC_InstallNoBinding TSRMLS_CC);
2013        return op_array;
2014    }
2015    /* }}} */
2016#ifdef SHOW_DPRINT
2017    compiler->new_entry.php = &compiler->new_php;
2018    xc_dprint(&compiler->new_entry, 0 TSRMLS_CC);
2019#endif
2020    ENTER_LOCK_EX(cache) { /* {{{ php_store/entry_store */
2021        /* php_store */
2022        stored_php = xc_php_store_unlocked(cache, &compiler->new_php TSRMLS_CC);
2023        if (!stored_php) {
2024            /* error */
2025            break;
2026        }
2027        /* entry_store */
2028        compiler->new_entry.php = stored_php;
2029        stored_entry = xc_entry_php_store_unlocked(cache, compiler->entry_hash.entryslotid, &compiler->new_entry TSRMLS_CC);
2030        if (stored_entry) {
2031            xc_php_addref_unlocked(stored_php);
2032            TRACE(" cached %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val);
2033            xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC);
2034        }
2035    } LEAVE_LOCK_EX(cache);
2036    /* }}} */
2037    TRACE("%s", stored_entry ? "stored" : "store failed");
2038
2039    cache->compiling = 0;
2040    if (catched) {
2041        goto err_aftersandbox;
2042    }
2043
2044    xc_free_php(&compiler->new_php TSRMLS_CC);
2045
2046    if (stored_entry) {
2047        if (op_array) {
2048#ifdef ZEND_ENGINE_2
2049            destroy_op_array(op_array TSRMLS_CC);
2050#else
2051            destroy_op_array(op_array);
2052#endif
2053            efree(op_array);
2054            h = NULL;
2055        }
2056        xc_sandbox_free(&sandbox, XC_NoInstall TSRMLS_CC);
2057        return xc_compile_restore(stored_entry, stored_php, h TSRMLS_CC);
2058    }
2059    else {
2060        zend_op_array *old_active_op_array = CG(active_op_array);
2061        /* install it */
2062        CG(active_op_array) = op_array;
2063        xc_sandbox_free(&sandbox, XC_Install TSRMLS_CC);
2064        CG(active_op_array) = old_active_op_array;
2065    }
2066    return op_array;
2067
2068err_aftersandbox:
2069    xc_free_php(&compiler->new_php TSRMLS_CC);
2070    xc_sandbox_free(&sandbox, XC_NoInstall TSRMLS_CC);
2071
2072    if (catched) {
2073        cache->compiling = 0;
2074        cache->errors ++;
2075        zend_bailout();
2076    }
2077    return op_array;
2078}
2079/* }}} */
2080static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
2081{
2082    xc_compiler_t compiler;
2083    zend_op_array *op_array;
2084
2085    assert(xc_initized);
2086
2087    TRACE("xc_compile_file: type=%d name=%s", h->type, h->filename ? h->filename : "NULL");
2088
2089    if (!XG(cacher)
2090     || !h->filename
2091     || !SG(request_info).path_translated
2092     || strstr(h->filename, "://") != NULL
2093#ifdef ZEND_ENGINE_2_3
2094     /* supported by php_resolve_path */
2095     || (!XG(stat) && strstr(PG(include_path), "://") != NULL)
2096#else
2097     || strstr(PG(include_path), "://") != NULL
2098#endif
2099     ) {
2100        op_array = old_compile_file(h, type TSRMLS_CC);
2101        TRACE("%s", "cacher not enabled");
2102        return op_array;
2103    }
2104
2105    /* {{{ entry_init_key */
2106    compiler.opened_path = h->opened_path;
2107    compiler.filename = compiler.opened_path ? compiler.opened_path : h->filename;
2108    compiler.filename_len = strlen(compiler.filename);
2109    if (xc_entry_php_init_key(&compiler TSRMLS_CC) != SUCCESS) {
2110        TRACE("failed to init key for %s", compiler.filename);
2111        return old_compile_file(h, type TSRMLS_CC);
2112    }
2113    /* }}} */
2114
2115    op_array = xc_compile_file_ex(&compiler, h, type TSRMLS_CC);
2116
2117    xc_entry_free_key_php(&compiler.new_entry TSRMLS_CC);
2118
2119    return op_array;
2120}
2121/* }}} */
2122
2123/* gdb helper functions, but N/A for coredump */
2124int xc_is_rw(const void *p) /* {{{ */
2125{
2126    xc_shm_t *shm;
2127    int i;
2128
2129    if (xc_php_caches) {
2130        for (i = 0; i < xc_php_hcache.size; i ++) {
2131            shm = xc_php_caches[i]->shm;
2132            if (shm->handlers->is_readwrite(shm, p)) {
2133                return 1;
2134            }
2135        }
2136    }
2137
2138    if (xc_var_caches) {
2139        for (i = 0; i < xc_var_hcache.size; i ++) {
2140            shm = xc_var_caches[i]->shm;
2141            if (shm->handlers->is_readwrite(shm, p)) {
2142                return 1;
2143            }
2144        }
2145    }
2146    return 0;
2147}
2148/* }}} */
2149int xc_is_ro(const void *p) /* {{{ */
2150{
2151    xc_shm_t *shm;
2152    int i;
2153
2154    if (xc_php_caches) {
2155        for (i = 0; i < xc_php_hcache.size; i ++) {
2156            shm = xc_php_caches[i]->shm;
2157            if (shm->handlers->is_readonly(shm, p)) {
2158                return 1;
2159            }
2160        }
2161    }
2162
2163    if (xc_var_caches) {
2164        for (i = 0; i < xc_var_hcache.size; i ++) {
2165            shm = xc_var_caches[i]->shm;
2166            if (shm->handlers->is_readonly(shm, p)) {
2167                return 1;
2168            }
2169        }
2170    }
2171    return 0;
2172}
2173/* }}} */
2174int xc_is_shm(const void *p) /* {{{ */
2175{
2176    return xc_is_ro(p) || xc_is_rw(p);
2177}
2178/* }}} */
2179
2180void xc_gc_add_op_array(xc_gc_op_array_t *gc_op_array TSRMLS_DC) /* {{{ */
2181{
2182    zend_llist_add_element(&XG(gc_op_arrays), (void *) gc_op_array);
2183}
2184/* }}} */
2185static void xc_gc_op_array(void *pDest) /* {{{ */
2186{
2187    xc_gc_op_array_t *op_array = (xc_gc_op_array_t *) pDest;
2188    zend_uint i;
2189#ifdef ZEND_ENGINE_2
2190    if (op_array->arg_info) {
2191        for (i = 0; i < op_array->num_args; i++) {
2192            efree((char *) ZSTR_V(op_array->arg_info[i].name));
2193            if (ZSTR_V(op_array->arg_info[i].class_name)) {
2194                efree((char *) ZSTR_V(op_array->arg_info[i].class_name));
2195            }
2196        }
2197        efree(op_array->arg_info);
2198    }
2199#endif
2200    if (op_array->opcodes) {
2201        efree(op_array->opcodes);
2202    }
2203}
2204/* }}} */
2205
2206/* module helper function */
2207static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
2208{
2209    typedef struct {
2210        const char *prefix;
2211        zend_uchar (*getsize)();
2212        const char *(*get)(zend_uchar i);
2213    } xc_meminfo_t;
2214    xc_meminfo_t nameinfos[] = {
2215        { "",        xc_get_op_type_count,   xc_get_op_type   },
2216        { "",        xc_get_data_type_count, xc_get_data_type },
2217        { "",        xc_get_opcode_count,    xc_get_opcode    },
2218        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
2219        { NULL, NULL, NULL }
2220    };
2221    xc_meminfo_t* p;
2222    zend_uchar i, count;
2223    char const_name[96];
2224    int const_name_len;
2225    int undefdone = 0;
2226
2227    for (p = nameinfos; p->getsize; p ++) {
2228        count = p->getsize();
2229        for (i = 0; i < count; i ++) {
2230            const char *name = p->get(i);
2231            if (!name) continue;
2232            if (strcmp(name, "UNDEF") == 0) {
2233                if (undefdone) continue;
2234                undefdone = 1;
2235            }
2236            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
2237            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
2238        }
2239    }
2240
2241    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
2242    zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
2243    zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
2244    zend_register_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
2245    zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
2246    return 0;
2247}
2248/* }}} */
2249static xc_shm_t *xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */
2250{
2251    int i;
2252    xc_cache_t *cache;
2253    xc_shm_t *shm;
2254
2255    if (!caches) {
2256        return NULL;
2257    }
2258    shm = NULL;
2259    for (i = 0; i < hcache->size; i ++) {
2260        cache = caches[i];
2261        if (cache) {
2262            if (cache->lck) {
2263                xc_lock_destroy(cache->lck);
2264            }
2265            /* do NOT free
2266            if (cache->entries) {
2267                cache->mem->handlers->free(cache->mem, cache->entries);
2268            }
2269            cache->mem->handlers->free(cache->mem, cache);
2270            */
2271            shm = cache->shm;
2272            shm->handlers->memdestroy(cache->mem);
2273        }
2274    }
2275    free(caches);
2276    return shm;
2277}
2278/* }}} */
2279static 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) /* {{{ */
2280{
2281    xc_cache_t **caches = NULL, *cache;
2282    xc_mem_t *mem;
2283    time_t now = time(NULL);
2284    int i;
2285    xc_memsize_t memsize;
2286
2287    memsize = shmsize / hcache->size;
2288
2289    /* Don't let it break out of mem after ALIGNed
2290     * This is important for
2291     * Simply loop until it fit our need
2292     */
2293    while (ALIGN(memsize) * hcache->size > shmsize && ALIGN(memsize) != memsize) {
2294        if (memsize < ALIGN(1)) {
2295            CHECK(NULL, "cache too small");
2296        }
2297        memsize --;
2298    }
2299
2300    CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");
2301
2302    for (i = 0; i < hcache->size; i ++) {
2303        CHECK(mem            = shm->handlers->meminit(shm, memsize), "Failed init memory allocator");
2304        CHECK(cache          = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");
2305        CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");
2306        if (hphp) {
2307            CHECK(cache->phps= mem->handlers->calloc(mem, hphp->size, sizeof(xc_entry_data_php_t*)), "phps OOM");
2308        }
2309        CHECK(cache->lck     = xc_lock_init(NULL), "can't create lock");
2310
2311        cache->hcache  = hcache;
2312        cache->hentry  = hentry;
2313        cache->hphp    = hphp;
2314        cache->shm     = shm;
2315        cache->mem     = mem;
2316        cache->cacheid = i;
2317        cache->last_gc_deletes = now;
2318        cache->last_gc_expires = now;
2319        caches[i] = cache;
2320    }
2321    return caches;
2322
2323err:
2324    if (caches) {
2325        xc_cache_destroy(caches, hcache);
2326    }
2327    return NULL;
2328}
2329/* }}} */
2330static void xc_destroy() /* {{{ */
2331{
2332    xc_shm_t *shm = NULL;
2333
2334    if (old_compile_file) {
2335        zend_compile_file = old_compile_file;
2336        old_compile_file = NULL;
2337    }
2338
2339    if (origin_compile_file) {
2340        zend_compile_file = origin_compile_file;
2341        origin_compile_file = NULL;
2342    }
2343
2344    if (xc_php_caches) {
2345        shm = xc_cache_destroy(xc_php_caches, &xc_php_hcache);
2346        xc_php_caches = NULL;
2347    }
2348
2349    if (xc_var_caches) {
2350        shm = xc_cache_destroy(xc_var_caches, &xc_var_hcache);
2351        xc_var_caches = NULL;
2352    }
2353
2354    if (shm) {
2355        xc_shm_destroy(shm);
2356    }
2357
2358    xc_initized = 0;
2359}
2360/* }}} */
2361static int xc_init(int module_number TSRMLS_DC) /* {{{ */
2362{
2363    xc_shm_t *shm;
2364    xc_shmsize_t shmsize = ALIGN(xc_php_size) + ALIGN(xc_var_size);
2365
2366    xc_php_caches = xc_var_caches = NULL;
2367    shm = NULL;
2368
2369    if (shmsize < (size_t) xc_php_size || shmsize < (size_t) xc_var_size) {
2370        zend_error(E_ERROR, "XCache: neither xcache.size nor xcache.var_size can be negative");
2371        goto err;
2372    }
2373
2374    if (xc_php_size || xc_var_size) {
2375        CHECK(shm = xc_shm_init(xc_shm_scheme, shmsize, xc_readonly_protection, xc_mmap_path, NULL), "Cannot create shm");
2376        if (!shm->handlers->can_readonly(shm)) {
2377            xc_readonly_protection = 0;
2378        }
2379
2380        if (xc_php_size) {
2381            old_compile_file = zend_compile_file;
2382            zend_compile_file = xc_compile_file;
2383
2384            CHECK(xc_php_caches = xc_cache_init(shm, &xc_php_hcache, &xc_php_hentry, &xc_php_hentry, xc_php_size), "failed init opcode cache");
2385        }
2386
2387        if (xc_var_size) {
2388            CHECK(xc_var_caches = xc_cache_init(shm, &xc_var_hcache, &xc_var_hentry, NULL, xc_var_size), "failed init variable cache");
2389        }
2390    }
2391    return SUCCESS;
2392
2393err:
2394    if (xc_php_caches || xc_var_caches) {
2395        xc_destroy();
2396        /* shm destroied in xc_destroy() */
2397    }
2398    else if (shm) {
2399        xc_destroy();
2400        xc_shm_destroy(shm);
2401    }
2402    return 0;
2403}
2404/* }}} */
2405static void xc_request_init(TSRMLS_D) /* {{{ */
2406{
2407    int i;
2408
2409    if (!XG(internal_table_copied)) {
2410        zend_function tmp_func;
2411        xc_cest_t tmp_cest;
2412
2413#ifdef HAVE_XCACHE_CONSTANT
2414        zend_hash_destroy(&XG(internal_constant_table));
2415#endif
2416        zend_hash_destroy(&XG(internal_function_table));
2417        zend_hash_destroy(&XG(internal_class_table));
2418
2419#ifdef HAVE_XCACHE_CONSTANT
2420        zend_hash_init_ex(&XG(internal_constant_table), 20,  NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
2421#endif
2422        zend_hash_init_ex(&XG(internal_function_table), 100, NULL, NULL, 1, 0);
2423        zend_hash_init_ex(&XG(internal_class_table),    10,  NULL, NULL, 1, 0);
2424
2425#ifdef HAVE_XCACHE_CONSTANT
2426        xc_copy_internal_zend_constants(&XG(internal_constant_table), EG(zend_constants));
2427#endif
2428        zend_hash_copy(&XG(internal_function_table), CG(function_table), NULL, &tmp_func, sizeof(tmp_func));
2429        zend_hash_copy(&XG(internal_class_table), CG(class_table), NULL, &tmp_cest, sizeof(tmp_cest));
2430
2431        XG(internal_table_copied) = 1;
2432    }
2433    if (xc_php_caches && !XG(php_holds)) {
2434        XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));
2435        for (i = 0; i < xc_php_hcache.size; i ++) {
2436            xc_stack_init(&XG(php_holds[i]));
2437        }
2438    }
2439
2440    if (xc_var_caches && !XG(var_holds)) {
2441        XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));
2442        for (i = 0; i < xc_var_hcache.size; i ++) {
2443            xc_stack_init(&XG(var_holds[i]));
2444        }
2445    }
2446
2447#ifdef ZEND_ENGINE_2
2448    zend_llist_init(&XG(gc_op_arrays), sizeof(xc_gc_op_array_t), xc_gc_op_array, 0);
2449#endif
2450
2451#if PHP_API_VERSION <= 20041225
2452    XG(request_time) = time(NULL);
2453#else
2454    XG(request_time) = sapi_get_request_time(TSRMLS_C);
2455#endif
2456
2457#ifdef HAVE_XCACHE_COVERAGER
2458    xc_coverager_request_init(TSRMLS_C);
2459#endif
2460}
2461/* }}} */
2462static void xc_request_shutdown(TSRMLS_D) /* {{{ */
2463{
2464    xc_entry_unholds(TSRMLS_C);
2465#ifdef ZEND_ENGINE_2
2466    zend_llist_destroy(&XG(gc_op_arrays));
2467#endif
2468    xc_gc_expires_php(TSRMLS_C);
2469    xc_gc_expires_var(TSRMLS_C);
2470    xc_gc_deletes(TSRMLS_C);
2471#ifdef HAVE_XCACHE_COVERAGER
2472    xc_coverager_request_shutdown(TSRMLS_C);
2473#endif
2474}
2475/* }}} */
2476/* {{{ PHP_GINIT_FUNCTION(xcache) */
2477static
2478#ifdef PHP_GINIT_FUNCTION
2479PHP_GINIT_FUNCTION(xcache)
2480#else
2481void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
2482#endif
2483{
2484    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
2485
2486#ifdef HAVE_XCACHE_CONSTANT
2487    zend_hash_init_ex(&xcache_globals->internal_constant_table, 1, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
2488#endif
2489    zend_hash_init_ex(&xcache_globals->internal_function_table, 1, NULL, NULL, 1, 0);
2490    zend_hash_init_ex(&xcache_globals->internal_class_table,    1, NULL, NULL, 1, 0);
2491}
2492/* }}} */
2493/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
2494static
2495#ifdef PHP_GSHUTDOWN_FUNCTION
2496PHP_GSHUTDOWN_FUNCTION(xcache)
2497#else
2498void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
2499#endif
2500{
2501    int i;
2502
2503    if (xcache_globals->php_holds != NULL) {
2504        for (i = 0; i < xc_php_hcache.size; i ++) {
2505            xc_stack_destroy(&xcache_globals->php_holds[i]);
2506        }
2507        free(xcache_globals->php_holds);
2508        xcache_globals->php_holds = NULL;
2509    }
2510
2511    if (xcache_globals->var_holds != NULL) {
2512        for (i = 0; i < xc_var_hcache.size; i ++) {
2513            xc_stack_destroy(&xcache_globals->var_holds[i]);
2514        }
2515        free(xcache_globals->var_holds);
2516        xcache_globals->var_holds = NULL;
2517    }
2518
2519    if (xcache_globals->internal_table_copied) {
2520#ifdef HAVE_XCACHE_CONSTANT
2521        zend_hash_destroy(&xcache_globals->internal_constant_table);
2522#endif
2523        zend_hash_destroy(&xcache_globals->internal_function_table);
2524        zend_hash_destroy(&xcache_globals->internal_class_table);
2525    }
2526}
2527/* }}} */
2528
2529/* user functions */
2530static int xcache_admin_auth_check(TSRMLS_D) /* {{{ */
2531{
2532    zval **server = NULL;
2533    zval **user = NULL;
2534    zval **pass = NULL;
2535    char *admin_user = NULL;
2536    char *admin_pass = NULL;
2537    HashTable *ht;
2538
2539    /* auth disabled, nothing to do.. */
2540    if (!XG(auth_enabled)) {
2541        return 1;
2542    }
2543
2544    if (cfg_get_string("xcache.admin.user", &admin_user) == FAILURE || !admin_user[0]) {
2545        admin_user = NULL;
2546    }
2547    if (cfg_get_string("xcache.admin.pass", &admin_pass) == FAILURE || !admin_pass[0]) {
2548        admin_pass = NULL;
2549    }
2550
2551    if (admin_user == NULL || admin_pass == NULL) {
2552        php_error_docref(XCACHE_WIKI_URL "/InstallAdministration" TSRMLS_CC, E_ERROR,
2553                "xcache.admin.user and/or xcache.admin.pass settings is not configured."
2554                " Make sure you've modified the correct php ini file for your php used in webserver.");
2555        zend_bailout();
2556    }
2557    if (strlen(admin_pass) != 32) {
2558        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));
2559        zend_bailout();
2560    }
2561
2562#ifdef ZEND_ENGINE_2_1
2563    zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
2564#endif
2565    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != SUCCESS || Z_TYPE_PP(server) != IS_ARRAY) {
2566        php_error_docref(NULL TSRMLS_CC, E_ERROR, "_SERVER is corrupted");
2567        zend_bailout();
2568    }
2569    ht = HASH_OF((*server));
2570
2571    if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
2572        user = NULL;
2573    }
2574    else if (Z_TYPE_PP(user) != IS_STRING) {
2575        user = NULL;
2576    }
2577
2578    if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {
2579        pass = NULL;
2580    }
2581    else if (Z_TYPE_PP(pass) != IS_STRING) {
2582        pass = NULL;
2583    }
2584
2585    if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {
2586        PHP_MD5_CTX context;
2587        char md5str[33];
2588        unsigned char digest[16];
2589
2590        PHP_MD5Init(&context);
2591        PHP_MD5Update(&context, (unsigned char *) Z_STRVAL_PP(pass), Z_STRLEN_PP(pass));
2592        PHP_MD5Final(digest, &context);
2593
2594        md5str[0] = '\0';
2595        make_digest(md5str, digest);
2596        if (strcmp(admin_pass, md5str) == 0) {
2597            return 1;
2598        }
2599    }
2600
2601#define STR "HTTP/1.0 401 Unauthorized"
2602    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
2603#undef STR
2604#define STR "WWW-authenticate: Basic Realm=\"XCache Administration\""
2605    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
2606#undef STR
2607#define STR "Content-type: text/html; charset=UTF-8"
2608    sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);
2609#undef STR
2610    ZEND_PUTS("<html>\n");
2611    ZEND_PUTS("<head><title>XCache Authentication Failed</title></head>\n");
2612    ZEND_PUTS("<body>\n");
2613    ZEND_PUTS("<h1>XCache Authentication Failed</h1>\n");
2614    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");
2615    ZEND_PUTS("<ul>\n");
2616    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");
2617    ZEND_PUTS("<li>Make sure the md5 password is generated correctly. You may use <a href=\"mkpassword.php\">mkpassword.php</a></li>\n");
2618    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");
2619    ZEND_PUTS("</ul>\n");
2620    ZEND_PUTS("Check <a href=\"" XCACHE_WIKI_URL "/InstallAdministration\">XCache wiki page</a> for more information.\n");
2621    ZEND_PUTS("</body>\n");
2622    ZEND_PUTS("</html>\n");
2623
2624    zend_bailout();
2625    return 0;
2626}
2627/* }}} */
2628/* {{{ xcache_admin_operate */
2629typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;
2630static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)
2631{
2632    long type;
2633    int size;
2634    xc_cache_t **caches, *cache;
2635    long id = 0;
2636
2637    xcache_admin_auth_check(TSRMLS_C);
2638
2639    if (!xc_initized) {
2640        RETURN_NULL();
2641    }
2642
2643    if (optype == XC_OP_COUNT) {
2644        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {
2645            return;
2646        }
2647    }
2648    else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {
2649        return;
2650    }
2651
2652    switch (type) {
2653        case XC_TYPE_PHP:
2654            size = xc_php_hcache.size;
2655            caches = xc_php_caches;
2656            break;
2657
2658        case XC_TYPE_VAR:
2659            size = xc_var_hcache.size;
2660            caches = xc_var_caches;
2661            break;
2662
2663        default:
2664            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);
2665            RETURN_FALSE;
2666    }
2667
2668    switch (optype) {
2669        case XC_OP_COUNT:
2670            RETURN_LONG(size)
2671            break;
2672
2673        case XC_OP_INFO:
2674        case XC_OP_LIST:
2675            if (id < 0 || id >= size) {
2676                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
2677                RETURN_FALSE;
2678            }
2679
2680            array_init(return_value);
2681
2682            cache = caches[id];
2683            ENTER_LOCK(cache) {
2684                if (optype == XC_OP_INFO) {
2685                    xc_fillinfo_unlocked(type, cache, return_value TSRMLS_CC);
2686                }
2687                else {
2688                    xc_filllist_unlocked(type, cache, return_value TSRMLS_CC);
2689                }
2690            } LEAVE_LOCK(cache);
2691            break;
2692        case XC_OP_CLEAR:
2693            {
2694                xc_entry_t *e, *next;
2695                int entryslotid, c;
2696
2697                if (id < 0 || id >= size) {
2698                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");
2699                    RETURN_FALSE;
2700                }
2701
2702                cache = caches[id];
2703                ENTER_LOCK(cache) {
2704                    for (entryslotid = 0, c = cache->hentry->size; entryslotid < c; entryslotid ++) {
2705                        for (e = cache->entries[entryslotid]; e; e = next) {
2706                            next = e->next;
2707                            xc_entry_remove_unlocked(type, cache, entryslotid, e TSRMLS_CC);
2708                        }
2709                        cache->entries[entryslotid] = NULL;
2710                    }
2711                } LEAVE_LOCK(cache);
2712                xc_gc_deletes(TSRMLS_C);
2713            }
2714            break;
2715
2716        default:
2717            assert(0);
2718    }
2719}
2720/* }}} */
2721/* {{{ proto int xcache_count(int type)
2722   Return count of cache on specified cache type */
2723PHP_FUNCTION(xcache_count)
2724{
2725    xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2726}
2727/* }}} */
2728/* {{{ proto array xcache_info(int type, int id)
2729   Get cache info by id on specified cache type */
2730PHP_FUNCTION(xcache_info)
2731{
2732    xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2733}
2734/* }}} */
2735/* {{{ proto array xcache_list(int type, int id)
2736   Get cache entries list by id on specified cache type */
2737PHP_FUNCTION(xcache_list)
2738{
2739    xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2740}
2741/* }}} */
2742/* {{{ proto array xcache_clear_cache(int type, int id)
2743   Clear cache by id on specified cache type */
2744PHP_FUNCTION(xcache_clear_cache)
2745{
2746    xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
2747}
2748/* }}} */
2749
2750#define VAR_DISABLED_WARNING() do { \
2751        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.var_size is either 0 or too small to enable var data caching"); \
2752} while (0)
2753
2754static int xc_entry_var_init_key(xc_entry_var_t *entry_var, xc_entry_hash_t *entry_hash, zval *name TSRMLS_DC) /* {{{ */
2755{
2756    xc_hash_value_t hv;
2757
2758    switch (name->type) {
2759#ifdef IS_UNICODE
2760        case IS_UNICODE:
2761        case IS_STRING:
2762#endif
2763        default:
2764#ifdef IS_UNICODE
2765            convert_to_unicode(name);
2766#else
2767            convert_to_string(name);
2768#endif
2769    }
2770
2771#ifdef IS_UNICODE
2772    entry_var->name_type = name->type;
2773#endif
2774    entry_var->entry.name = name->value;
2775
2776    hv = xc_entry_hash_var((xc_entry_t *) entry_var TSRMLS_CC);
2777
2778    entry_hash->cacheid = (hv & xc_var_hcache.mask);
2779    hv >>= xc_var_hcache.bits;
2780    entry_hash->entryslotid = (hv & xc_var_hentry.mask);
2781    return SUCCESS;
2782}
2783/* }}} */
2784/* {{{ proto mixed xcache_get(string name)
2785   Get cached data by specified name */
2786PHP_FUNCTION(xcache_get)
2787{
2788    xc_entry_hash_t entry_hash;
2789    xc_cache_t *cache;
2790    xc_entry_var_t entry_var, *stored_entry_var;
2791    zval *name;
2792
2793    if (!xc_var_caches) {
2794        VAR_DISABLED_WARNING();
2795        RETURN_NULL();
2796    }
2797
2798    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
2799        return;
2800    }
2801    xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
2802    cache = xc_var_caches[entry_hash.cacheid];
2803
2804    ENTER_LOCK(cache) {
2805        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);
2806        if (stored_entry_var) {
2807            /* return */
2808            xc_processor_restore_zval(return_value, stored_entry_var->value, stored_entry_var->have_references TSRMLS_CC);
2809            xc_cache_hit_unlocked(cache TSRMLS_CC);
2810        }
2811        else {
2812            RETVAL_NULL();
2813            cache->misses ++;
2814        }
2815    } LEAVE_LOCK(cache);
2816}
2817/* }}} */
2818/* {{{ proto bool  xcache_set(string name, mixed value [, int ttl])
2819   Store data to cache by specified name */
2820PHP_FUNCTION(xcache_set)
2821{
2822    xc_entry_hash_t entry_hash;
2823    xc_cache_t *cache;
2824    xc_entry_var_t entry_var, *stored_entry_var;
2825    zval *name;
2826    zval *value;
2827
2828    if (!xc_var_caches) {
2829        VAR_DISABLED_WARNING();
2830        RETURN_NULL();
2831    }
2832
2833    entry_var.entry.ttl = XG(var_ttl);
2834    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &entry_var.entry.ttl) == FAILURE) {
2835        return;
2836    }
2837
2838    /* max ttl */
2839    if (xc_var_maxttl && (!entry_var.entry.ttl || entry_var.entry.ttl > xc_var_maxttl)) {
2840        entry_var.entry.ttl = xc_var_maxttl;
2841    }
2842
2843    xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
2844    cache = xc_var_caches[entry_hash.cacheid];
2845
2846    ENTER_LOCK(cache) {
2847        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);
2848        if (stored_entry_var) {
2849            xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);
2850        }
2851        entry_var.value = value;
2852        RETVAL_BOOL(xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC) != NULL ? 1 : 0);
2853    } LEAVE_LOCK(cache);
2854}
2855/* }}} */
2856/* {{{ proto bool  xcache_isset(string name)
2857   Check if an entry exists in cache by specified name */
2858PHP_FUNCTION(xcache_isset)
2859{
2860    xc_entry_hash_t entry_hash;
2861    xc_cache_t *cache;
2862    xc_entry_var_t entry_var, *stored_entry_var;
2863    zval *name;
2864
2865    if (!xc_var_caches) {
2866        VAR_DISABLED_WARNING();
2867        RETURN_FALSE;
2868    }
2869
2870    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
2871        return;
2872    }
2873    xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
2874    cache = xc_var_caches[entry_hash.cacheid];
2875
2876    ENTER_LOCK(cache) {
2877        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);
2878        if (stored_entry_var) {
2879            xc_cache_hit_unlocked(cache TSRMLS_CC);
2880            RETVAL_TRUE;
2881            /* return */
2882        }
2883        else {
2884            RETVAL_FALSE;
2885        }
2886
2887    } LEAVE_LOCK(cache);
2888}
2889/* }}} */
2890/* {{{ proto bool  xcache_unset(string name)
2891   Unset existing data in cache by specified name */
2892PHP_FUNCTION(xcache_unset)
2893{
2894    xc_entry_hash_t entry_hash;
2895    xc_cache_t *cache;
2896    xc_entry_var_t entry_var, *stored_entry_var;
2897    zval *name;
2898
2899    if (!xc_var_caches) {
2900        VAR_DISABLED_WARNING();
2901        RETURN_FALSE;
2902    }
2903
2904    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
2905        return;
2906    }
2907    xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
2908    cache = xc_var_caches[entry_hash.cacheid];
2909
2910    ENTER_LOCK(cache) {
2911        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);
2912        if (stored_entry_var) {
2913            xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);
2914            RETVAL_TRUE;
2915        }
2916        else {
2917            RETVAL_FALSE;
2918        }
2919    } LEAVE_LOCK(cache);
2920}
2921/* }}} */
2922/* {{{ proto bool  xcache_unset_by_prefix(string prefix)
2923   Unset existing data in cache by specified prefix */
2924PHP_FUNCTION(xcache_unset_by_prefix)
2925{
2926    zval *prefix;
2927    int i, iend;
2928
2929    if (!xc_var_caches) {
2930        VAR_DISABLED_WARNING();
2931        RETURN_FALSE;
2932    }
2933
2934    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &prefix) == FAILURE) {
2935        return;
2936    }
2937
2938    for (i = 0, iend = xc_var_hcache.size; i < iend; i ++) {
2939        xc_cache_t *cache = xc_var_caches[i];
2940        ENTER_LOCK(cache) {
2941            int entryslotid, jend;
2942            for (entryslotid = 0, jend = cache->hentry->size; entryslotid < jend; entryslotid ++) {
2943                xc_entry_t *entry, *next;
2944                for (entry = cache->entries[entryslotid]; entry; entry = next) {
2945                    next = entry->next;
2946                    if (xc_entry_has_prefix_unlocked(XC_TYPE_VAR, entry, prefix)) {
2947                        xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entryslotid, entry TSRMLS_CC);
2948                    }
2949                }
2950            }
2951        } LEAVE_LOCK(cache);
2952    }
2953}
2954/* }}} */
2955static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
2956{
2957    xc_entry_hash_t entry_hash;
2958    xc_cache_t *cache;
2959    xc_entry_var_t entry_var, *stored_entry_var;
2960    zval *name;
2961    long count = 1;
2962    long value = 0;
2963    zval oldzval;
2964
2965    if (!xc_var_caches) {
2966        VAR_DISABLED_WARNING();
2967        RETURN_NULL();
2968    }
2969
2970    entry_var.entry.ttl = XG(var_ttl);
2971    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &entry_var.entry.ttl) == FAILURE) {
2972        return;
2973    }
2974
2975    /* max ttl */
2976    if (xc_var_maxttl && (!entry_var.entry.ttl || entry_var.entry.ttl > xc_var_maxttl)) {
2977        entry_var.entry.ttl = xc_var_maxttl;
2978    }
2979
2980    xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
2981    cache = xc_var_caches[entry_hash.cacheid];
2982
2983    ENTER_LOCK(cache) {
2984        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);
2985        if (stored_entry_var) {
2986            TRACE("incdec: got entry_var %s", entry_var.entry.name.str.val);
2987            /* do it in place */
2988            if (Z_TYPE_P(stored_entry_var->value) == IS_LONG) {
2989                zval *zv;
2990                stored_entry_var->entry.ctime = XG(request_time);
2991                stored_entry_var->entry.ttl   = entry_var.entry.ttl;
2992                TRACE("%s", "incdec: islong");
2993                value = Z_LVAL_P(stored_entry_var->value);
2994                value += (inc == 1 ? count : - count);
2995                RETVAL_LONG(value);
2996
2997                zv = (zval *) cache->shm->handlers->to_readwrite(cache->shm, (char *) stored_entry_var->value);
2998                Z_LVAL_P(zv) = value;
2999                break; /* leave lock */
3000            }
3001
3002            TRACE("%s", "incdec: notlong");
3003            xc_processor_restore_zval(&oldzval, stored_entry_var->value, stored_entry_var->have_references TSRMLS_CC);
3004            convert_to_long(&oldzval);
3005            value = Z_LVAL(oldzval);
3006            zval_dtor(&oldzval);
3007        }
3008        else {
3009            TRACE("incdec: %s not found", entry_var.entry.name.str.val);
3010        }
3011
3012        value += (inc == 1 ? count : - count);
3013        RETVAL_LONG(value);
3014        entry_var.value = return_value;
3015
3016        if (stored_entry_var) {
3017            entry_var.entry.atime = stored_entry_var->entry.atime;
3018            entry_var.entry.ctime = stored_entry_var->entry.ctime;
3019            entry_var.entry.hits  = stored_entry_var->entry.hits;
3020            xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);
3021        }
3022        xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC);
3023    } LEAVE_LOCK(cache);
3024}
3025/* }}} */
3026/* {{{ proto int xcache_inc(string name [, int value [, int ttl]])
3027   Increase an int counter in cache by specified name, create it if not exists */
3028PHP_FUNCTION(xcache_inc)
3029{
3030    xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
3031}
3032/* }}} */
3033/* {{{ proto int xcache_dec(string name [, int value [, int ttl]])
3034   Decrease an int counter in cache by specified name, create it if not exists */
3035PHP_FUNCTION(xcache_dec)
3036{
3037    xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
3038}
3039/* }}} */
3040/* {{{ proto int xcache_get_refcount(mixed variable)
3041   XCache internal uses only: Get reference count of variable */
3042PHP_FUNCTION(xcache_get_refcount)
3043{
3044    zval *variable;
3045    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
3046        RETURN_NULL();
3047    }
3048
3049    RETURN_LONG(Z_REFCOUNT(*variable));
3050}
3051/* }}} */
3052/* {{{ proto bool xcache_get_isref(mixed variable)
3053   XCache internal uses only: Check if variable data is marked referenced */
3054ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_isref, 0, 0, 1)
3055    ZEND_ARG_INFO(1, variable)
3056ZEND_END_ARG_INFO()
3057
3058PHP_FUNCTION(xcache_get_isref)
3059{
3060    zval *variable;
3061    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
3062        RETURN_NULL();
3063    }
3064
3065    RETURN_BOOL(Z_ISREF(*variable) && Z_REFCOUNT(*variable) >= 3);
3066}
3067/* }}} */
3068#ifdef HAVE_XCACHE_DPRINT
3069/* {{{ proto bool  xcache_dprint(mixed value)
3070   Prints variable (or value) internal struct (debug only) */
3071PHP_FUNCTION(xcache_dprint)
3072{
3073    zval *value;
3074
3075    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
3076        return;
3077    }
3078    xc_dprint_zval(value, 0 TSRMLS_CC);
3079}
3080/* }}} */
3081#endif
3082/* {{{ proto string xcache_asm(string filename)
3083 */
3084#ifdef HAVE_XCACHE_ASSEMBLER
3085PHP_FUNCTION(xcache_asm)
3086{
3087}
3088#endif
3089/* }}} */
3090#ifdef HAVE_XCACHE_DISASSEMBLER
3091/* {{{ proto array  xcache_dasm_file(string filename)
3092   Disassemble file into opcode array by filename */
3093PHP_FUNCTION(xcache_dasm_file)
3094{
3095    char *filename;
3096    int filename_len;
3097
3098    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
3099        return;
3100    }
3101    if (!filename_len) RETURN_FALSE;
3102
3103    xc_dasm_file(return_value, filename TSRMLS_CC);
3104}
3105/* }}} */
3106/* {{{ proto array  xcache_dasm_string(string code)
3107   Disassemble php code into opcode array */
3108PHP_FUNCTION(xcache_dasm_string)
3109{
3110    zval *code;
3111
3112    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) {
3113        return;
3114    }
3115    xc_dasm_string(return_value, code TSRMLS_CC);
3116}
3117/* }}} */
3118#endif
3119/* {{{ proto string xcache_encode(string filename)
3120   Encode php file into XCache opcode encoded format */
3121#ifdef HAVE_XCACHE_ENCODER
3122PHP_FUNCTION(xcache_encode)
3123{
3124}
3125#endif
3126/* }}} */
3127/* {{{ proto bool xcache_decode_file(string filename)
3128   Decode(load) opcode from XCache encoded format file */
3129#ifdef HAVE_XCACHE_DECODER
3130PHP_FUNCTION(xcache_decode_file)
3131{
3132}
3133#endif
3134/* }}} */
3135/* {{{ proto bool xcache_decode_string(string data)
3136   Decode(load) opcode from XCache encoded format data */
3137#ifdef HAVE_XCACHE_DECODER
3138PHP_FUNCTION(xcache_decode_string)
3139{
3140}
3141#endif
3142/* }}} */
3143/* {{{ xc_call_getter */
3144typedef const char *(xc_name_getter_t)(zend_uchar type);
3145static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
3146{
3147    long spec;
3148    const char *name;
3149
3150    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
3151        return;
3152    }
3153    if (spec >= 0 && spec < count) {
3154        name = getter((zend_uchar) spec);
3155        if (name) {
3156            /* RETURN_STRING */
3157            int len = strlen(name);
3158            return_value->value.str.len = len;
3159            return_value->value.str.val = estrndup(name, len);
3160            return_value->type = IS_STRING; 
3161            return;
3162        }
3163    }
3164    RETURN_NULL();
3165}
3166/* }}} */
3167/* {{{ proto string xcache_get_op_type(int op_type) */
3168PHP_FUNCTION(xcache_get_op_type)
3169{
3170    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
3171}
3172/* }}} */
3173/* {{{ proto string xcache_get_data_type(int type) */
3174PHP_FUNCTION(xcache_get_data_type)
3175{
3176    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
3177}
3178/* }}} */
3179/* {{{ proto string xcache_get_opcode(int opcode) */
3180PHP_FUNCTION(xcache_get_opcode)
3181{
3182    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
3183}
3184/* }}} */
3185/* {{{ proto string xcache_get_op_spec(int op_type) */
3186PHP_FUNCTION(xcache_get_op_spec)
3187{
3188    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
3189}
3190/* }}} */
3191#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
3192/* {{{ proto string xcache_get_opcode_spec(int opcode) */
3193PHP_FUNCTION(xcache_get_opcode_spec)
3194{
3195    long spec;
3196    const xc_opcode_spec_t *opspec;
3197
3198    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
3199        return;
3200    }
3201    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
3202        opspec = xc_get_opcode_spec((zend_uchar) spec);
3203        if (opspec) {
3204            array_init(return_value);
3205            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
3206            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
3207            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
3208            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
3209            return;
3210        }
3211    }
3212    RETURN_NULL();
3213}
3214/* }}} */
3215#endif
3216/* {{{ proto mixed xcache_get_special_value(zval value)
3217   XCache internal use only: For decompiler to get static value with type fixed */
3218PHP_FUNCTION(xcache_get_special_value)
3219{
3220    zval *value;
3221
3222    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
3223        return;
3224    }
3225
3226    switch ((Z_TYPE_P(value) & IS_CONSTANT_TYPE_MASK)) {
3227    case IS_CONSTANT:
3228        *return_value = *value;
3229        zval_copy_ctor(return_value);
3230        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
3231        break;
3232
3233    case IS_CONSTANT_ARRAY:
3234        *return_value = *value;
3235        zval_copy_ctor(return_value);
3236        return_value->type = IS_ARRAY;
3237        break;
3238
3239    default:
3240        RETURN_NULL();
3241    }
3242}
3243/* }}} */
3244/* {{{ proto int xcache_get_type(zval value)
3245   XCache internal use only for disassembler to get variable type in engine level */
3246PHP_FUNCTION(xcache_get_type)
3247{
3248    zval *value;
3249
3250    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
3251        return;
3252    }
3253
3254    RETURN_LONG(Z_TYPE_P(value));
3255}
3256/* }}} */
3257/* {{{ proto string xcache_coredump(int op_type) */
3258PHP_FUNCTION(xcache_coredump)
3259{
3260    if (xc_test) {
3261        raise(SIGSEGV);
3262    }
3263    else {
3264        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
3265    }
3266}
3267/* }}} */
3268/* {{{ proto string xcache_is_autoglobal(string name) */
3269PHP_FUNCTION(xcache_is_autoglobal)
3270{
3271    zval *name;
3272
3273    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
3274        return;
3275    }
3276
3277#ifdef IS_UNICODE
3278    convert_to_unicode(name);
3279#else
3280    convert_to_string(name);
3281#endif
3282
3283    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
3284}
3285/* }}} */
3286static zend_function_entry xcache_functions[] = /* {{{ */
3287{
3288    PHP_FE(xcache_count,             NULL)
3289    PHP_FE(xcache_info,              NULL)
3290    PHP_FE(xcache_list,              NULL)
3291    PHP_FE(xcache_clear_cache,       NULL)
3292    PHP_FE(xcache_coredump,          NULL)
3293#ifdef HAVE_XCACHE_ASSEMBLER
3294    PHP_FE(xcache_asm,               NULL)
3295#endif
3296#ifdef HAVE_XCACHE_DISASSEMBLER
3297    PHP_FE(xcache_dasm_file,         NULL)
3298    PHP_FE(xcache_dasm_string,       NULL)
3299#endif
3300#ifdef HAVE_XCACHE_ENCODER
3301    PHP_FE(xcache_encode,            NULL)
3302#endif
3303#ifdef HAVE_XCACHE_DECODER
3304    PHP_FE(xcache_decode_file,       NULL)
3305    PHP_FE(xcache_decode_string,     NULL)
3306#endif
3307#ifdef HAVE_XCACHE_COVERAGER
3308    PHP_FE(xcache_coverager_decode,  NULL)
3309    PHP_FE(xcache_coverager_start,   NULL)
3310    PHP_FE(xcache_coverager_stop,    NULL)
3311    PHP_FE(xcache_coverager_get,     NULL)
3312#endif
3313    PHP_FE(xcache_get_special_value, NULL)
3314    PHP_FE(xcache_get_type,          NULL)
3315    PHP_FE(xcache_get_op_type,       NULL)
3316    PHP_FE(xcache_get_data_type,     NULL)
3317    PHP_FE(xcache_get_opcode,        NULL)
3318#ifdef HAVE_XCACHE_OPCODE_SPEC_DEF
3319    PHP_FE(xcache_get_opcode_spec,   NULL)
3320#endif
3321    PHP_FE(xcache_is_autoglobal,     NULL)
3322    PHP_FE(xcache_inc,               NULL)
3323    PHP_FE(xcache_dec,               NULL)
3324    PHP_FE(xcache_get,               NULL)
3325    PHP_FE(xcache_set,               NULL)
3326    PHP_FE(xcache_isset,             NULL)
3327    PHP_FE(xcache_unset,             NULL)
3328    PHP_FE(xcache_unset_by_prefix,   NULL)
3329    PHP_FE(xcache_get_refcount,      NULL)
3330    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
3331#ifdef HAVE_XCACHE_DPRINT
3332    PHP_FE(xcache_dprint,            NULL)
3333#endif
3334    {NULL, NULL,                     NULL}
3335};
3336/* }}} */
3337
3338#ifdef ZEND_WIN32
3339#include "dbghelp.h"
3340typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
3341        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
3342        CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
3343        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
3344        );
3345
3346static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
3347static HMODULE dbghelpModule = NULL;
3348static char crash_dumpPath[_MAX_PATH] = { 0 };
3349static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
3350
3351static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
3352{
3353    HANDLE fileHandle;
3354
3355    SetUnhandledExceptionFilter(oldFilter);
3356
3357    /* create the file */
3358    fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3359
3360    if (fileHandle != INVALID_HANDLE_VALUE) {
3361        MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
3362        BOOL ok;
3363
3364        exceptionInformation.ThreadId = GetCurrentThreadId();
3365        exceptionInformation.ExceptionPointers = pExceptionInfo;
3366        exceptionInformation.ClientPointers = FALSE;
3367
3368        /* write the dump */
3369        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, MiniDumpNormal, &exceptionInformation, NULL, NULL);
3370        CloseHandle(fileHandle);
3371        if (ok) {
3372            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
3373            return EXCEPTION_EXECUTE_HANDLER;
3374        }
3375        else {
3376            zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
3377        }
3378    }
3379    else {
3380        zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
3381    }
3382
3383    return EXCEPTION_CONTINUE_SEARCH;
3384}
3385/* }}} */
3386
3387static void xcache_restore_crash_handler() /* {{{ */
3388{
3389    if (oldFilter) {
3390        SetUnhandledExceptionFilter(oldFilter);
3391        oldFilter = NULL;
3392    }
3393}
3394/* }}} */
3395static void xcache_init_crash_handler() /* {{{ */
3396{
3397    /* firstly see if dbghelp.dll is around and has the function we need
3398       look next to the EXE first, as the one in System32 might be old
3399       (e.g. Windows 2000) */
3400    char dbghelpPath[_MAX_PATH];
3401
3402    if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
3403        char *slash = strchr(dbghelpPath, '\\');
3404        if (slash) {
3405            strcpy(slash + 1, "DBGHELP.DLL");
3406            dbghelpModule = LoadLibrary(dbghelpPath);
3407        }
3408    }
3409
3410    if (!dbghelpModule) {
3411        /* load any version we can */
3412        dbghelpModule = LoadLibrary("DBGHELP.DLL");
3413        if (!dbghelpModule) {
3414            zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
3415            return;
3416        }
3417    }
3418
3419    dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
3420    if (dbghelp_MiniDumpWriteDump) {
3421        zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL too old");
3422        return;
3423    }
3424
3425    /* work out a good place for the dump file */
3426    {
3427        char tmpPath[_MAX_PATH];
3428        if (!GetTempPath(_MAX_PATH, tmpPath)) {
3429            strcpy(tmpPath, "c:\\temp");
3430        }
3431        sprintf(crash_dumpPath, "%s\\php-%s-xcache-%s-%lu.dmp", PHP_VERSION, XCACHE_VERSION, (unsigned long) GetCurrentProcessId());
3432    }
3433
3434    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
3435}
3436/* }}} */
3437#else
3438/* old signal handlers {{{ */
3439typedef void (*xc_sighandler_t)(int);
3440#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
3441#include "foreachcoresig.h"
3442#undef FOREACH_SIG
3443/* }}} */
3444static void xcache_signal_handler(int sig);
3445static void xcache_restore_crash_handler() /* {{{ */
3446{
3447#define FOREACH_SIG(sig) do { \
3448    if (old_##sig##_handler != xcache_signal_handler) { \
3449        signal(sig, old_##sig##_handler); \
3450    } \
3451    else { \
3452        signal(sig, SIG_DFL); \
3453    } \
3454} while (0)
3455#include "foreachcoresig.h"
3456#undef FOREACH_SIG
3457}
3458/* }}} */
3459static void xcache_init_crash_handler() /* {{{ */
3460{
3461#define FOREACH_SIG(sig) \
3462    old_##sig##_handler = signal(sig, xcache_signal_handler)
3463#include "foreachcoresig.h"
3464#undef FOREACH_SIG
3465}
3466/* }}} */
3467static void xcache_signal_handler(int sig) /* {{{ */
3468{
3469    xcache_restore_crash_handler();
3470    if (xc_coredump_dir && xc_coredump_dir[0]) {
3471        if (chdir(xc_coredump_dir) != 0) {
3472            /* error, but nothing can do about it
3473             * and should'nt print anything which might SEGV again */
3474        }
3475    }
3476    raise(sig);
3477}
3478/* }}} */
3479#endif
3480
3481/* {{{ PHP_INI */
3482
3483static PHP_INI_MH(xc_OnUpdateDummy)
3484{
3485    return SUCCESS;
3486}
3487
3488static PHP_INI_MH(xc_OnUpdateULong)
3489{
3490    zend_ulong *p = (zend_ulong *) mh_arg1;
3491
3492    *p = (zend_ulong) atoi(new_value);
3493    return SUCCESS;
3494}
3495
3496static PHP_INI_MH(xc_OnUpdateBool)
3497{
3498    zend_bool *p = (zend_bool *)mh_arg1;
3499
3500    if (strncasecmp("on", new_value, sizeof("on"))) {
3501        *p = (zend_bool) atoi(new_value);
3502    }
3503    else {
3504        *p = (zend_bool) 1;
3505    }
3506    return SUCCESS;
3507}
3508
3509static PHP_INI_MH(xc_OnUpdateString)
3510{
3511    char **p = (char**)mh_arg1;
3512    if (*p) {
3513        pefree(*p, 1);
3514    }
3515    *p = pemalloc(strlen(new_value) + 1, 1);
3516    strcpy(*p, new_value);
3517    return SUCCESS;
3518}
3519
3520#ifndef ZEND_ENGINE_2
3521#define OnUpdateLong OnUpdateInt
3522#endif
3523
3524#ifdef ZEND_WIN32
3525#   define DEFAULT_PATH "xcache"
3526#else
3527#   define DEFAULT_PATH "/dev/zero"
3528#endif
3529PHP_INI_BEGIN()
3530    PHP_INI_ENTRY1     ("xcache.mmap_path",     DEFAULT_PATH, PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_mmap_path)
3531    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_coredump_dir)
3532    PHP_INI_ENTRY1     ("xcache.test",                   "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_test)
3533    PHP_INI_ENTRY1     ("xcache.readonly_protection",    "0", PHP_INI_SYSTEM, xc_OnUpdateBool,     &xc_readonly_protection)
3534    /* opcode cache */
3535    PHP_INI_ENTRY1     ("xcache.size",                   "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
3536    PHP_INI_ENTRY1     ("xcache.count",                  "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
3537    PHP_INI_ENTRY1     ("xcache.slots",                 "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
3538    PHP_INI_ENTRY1     ("xcache.shm_scheme",          "mmap", PHP_INI_SYSTEM, xc_OnUpdateString,   &xc_shm_scheme)
3539    PHP_INI_ENTRY1     ("xcache.ttl",                    "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_ttl)
3540    PHP_INI_ENTRY1     ("xcache.gc_interval",            "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_php_gc_interval)
3541    /* var cache */
3542    PHP_INI_ENTRY1     ("xcache.var_size",               "0", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
3543    PHP_INI_ENTRY1     ("xcache.var_count",              "1", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
3544    PHP_INI_ENTRY1     ("xcache.var_slots",             "8K", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
3545    PHP_INI_ENTRY1     ("xcache.var_maxttl",             "0", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_maxttl)
3546    PHP_INI_ENTRY1     ("xcache.var_gc_interval",      "120", PHP_INI_SYSTEM, xc_OnUpdateULong,    &xc_var_gc_interval)
3547
3548    STD_PHP_INI_BOOLEAN("xcache.cacher",                 "1", PHP_INI_ALL,    OnUpdateBool,        cacher,            zend_xcache_globals, xcache_globals)
3549    STD_PHP_INI_BOOLEAN("xcache.stat",                   "1", PHP_INI_ALL,    OnUpdateBool,        stat,              zend_xcache_globals, xcache_globals)
3550    STD_PHP_INI_BOOLEAN("xcache.admin.enable_auth",      "1", PHP_INI_SYSTEM, OnUpdateBool,        auth_enabled,      zend_xcache_globals, xcache_globals)
3551    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
3552#ifdef HAVE_XCACHE_OPTIMIZER
3553    STD_PHP_INI_BOOLEAN("xcache.optimizer",              "0", PHP_INI_ALL,    OnUpdateBool,        optimizer,         zend_xcache_globals, xcache_globals)
3554#endif
3555    STD_PHP_INI_ENTRY  ("xcache.var_ttl",                "0", PHP_INI_ALL,    OnUpdateLong,        var_ttl,           zend_xcache_globals, xcache_globals)
3556#ifdef HAVE_XCACHE_COVERAGER
3557    STD_PHP_INI_BOOLEAN("xcache.coverager"      ,        "0", PHP_INI_ALL,    OnUpdateBool,        coverager,         zend_xcache_globals, xcache_globals)
3558    PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xc_OnUpdateDummy,    NULL)
3559#endif
3560PHP_INI_END()
3561/* }}} */
3562/* {{{ PHP_MINFO_FUNCTION(xcache) */
3563static PHP_MINFO_FUNCTION(xcache)
3564{
3565    char buf[100];
3566    char *ptr;
3567    int left, len;
3568    xc_shm_scheme_t *scheme;
3569#ifdef HAVE_XCACHE_COVERAGER
3570    char *covdumpdir;
3571#endif
3572
3573    php_info_print_table_start();
3574    php_info_print_table_header(2, "XCache Support", "enabled");
3575    php_info_print_table_row(2, "Version", XCACHE_VERSION);
3576    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
3577    php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "N/A");
3578#ifdef ZEND_ENGINE_2_1
3579    ptr = php_format_date("Y-m-d H:i:s", sizeof("Y-m-d H:i:s") - 1, xc_init_time, 1 TSRMLS_CC);
3580    php_info_print_table_row(2, "Cache Init Time", ptr);
3581    efree(ptr);
3582#else
3583    snprintf(buf, sizeof(buf), "%lu", (long unsigned) xc_init_time);
3584    php_info_print_table_row(2, "Cache Init Time", buf);
3585#endif
3586
3587#ifdef ZTS
3588    snprintf(buf, sizeof(buf), "%lu.%lu", xc_init_instance_id, xc_init_instance_subid);
3589#else
3590    snprintf(buf, sizeof(buf), "%lu", xc_init_instance_id);
3591#endif
3592    php_info_print_table_row(2, "Cache Instance Id", buf);
3593
3594    if (xc_php_size) {
3595        ptr = _php_math_number_format(xc_php_size, 0, '.', ',');
3596        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_php_hcache.size, xc_php_hentry.size);
3597        php_info_print_table_row(2, "Opcode Cache", buf);
3598        efree(ptr);
3599    }
3600    else {
3601        php_info_print_table_row(2, "Opcode Cache", "disabled");
3602    }
3603    if (xc_var_size) {
3604        ptr = _php_math_number_format(xc_var_size, 0, '.', ',');
3605        snprintf(buf, sizeof(buf), "enabled, %s bytes, %d split(s), with %d slots each", ptr, xc_var_hcache.size, xc_var_hentry.size);
3606        php_info_print_table_row(2, "Variable Cache", buf);
3607        efree(ptr);
3608    }
3609    else {
3610        php_info_print_table_row(2, "Variable Cache", "disabled");
3611    }
3612
3613    left = sizeof(buf);
3614    ptr = buf;
3615    buf[0] = '\0';
3616    for (scheme = xc_shm_scheme_first(); scheme; scheme = xc_shm_scheme_next(scheme)) {
3617        len = snprintf(ptr, left, ptr == buf ? "%s" : ", %s", xc_shm_scheme_name(scheme));
3618        left -= len;
3619        ptr += len;
3620    }
3621    php_info_print_table_row(2, "Shared Memory Schemes", buf);
3622
3623#ifdef HAVE_XCACHE_COVERAGER
3624    if (cfg_get_string("xcache.coveragedump_directory", &covdumpdir) != SUCCESS || !covdumpdir[0]) {
3625        covdumpdir = NULL;
3626    }
3627    php_info_print_table_row(2, "Coverage Auto Dumper", XG(coverager) && covdumpdir ? "enabled" : "disabled");
3628#endif
3629    php_info_print_table_end();
3630
3631    DISPLAY_INI_ENTRIES();
3632}
3633/* }}} */
3634/* {{{ extension startup */
3635static void xc_zend_extension_register(zend_extension *new_extension, DL_HANDLE handle)
3636{
3637    zend_extension extension;
3638
3639    extension = *new_extension;
3640    extension.handle = handle;
3641
3642    zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
3643
3644    zend_llist_prepend_element(&zend_extensions, &extension);
3645    TRACE("%s", "registered");
3646}
3647
3648static zend_llist_element *xc_llist_get_element_by_zend_extension(zend_llist *l, const char *extension_name)
3649{
3650    zend_llist_element *element;
3651
3652    for (element = zend_extensions.head; element; element = element->next) {
3653        zend_extension *extension = (zend_extension *) element->data;
3654
3655        if (!strcmp(extension->name, extension_name)) {
3656            return element;
3657        }
3658    }
3659    return NULL;
3660}
3661
3662static void xc_llist_prepend(zend_llist *l, zend_llist_element *element)
3663{
3664    element->next = l->head;
3665    element->prev = NULL;
3666    if (l->head) {
3667        l->head->prev = element;
3668    }
3669    else {
3670        l->tail = element;
3671    }
3672    l->head = element;
3673    ++l->count;
3674}
3675
3676static void xc_llist_unlink(zend_llist *l, zend_llist_element *element)
3677{
3678    if ((element)->prev) {
3679        (element)->prev->next = (element)->next;
3680    }
3681    else {
3682        (l)->head = (element)->next;
3683    }
3684
3685    if ((element)->next) {
3686        (element)->next->prev = (element)->prev;
3687    }
3688    else {
3689        (l)->tail = (element)->prev;
3690    }
3691
3692    --l->count;
3693}
3694
3695static int xc_zend_extension_startup(zend_extension *extension)
3696{
3697    if (extension->startup) {
3698        if (extension->startup(extension) != SUCCESS) {
3699            return FAILURE;
3700        }
3701    }
3702    return SUCCESS;
3703}
3704/* }}} */
3705static int xc_ptr_compare_func(void *p1, void *p2) /* {{{ */
3706{
3707    return p1 == p2;
3708}
3709/* }}} */
3710static int xc_zend_remove_extension(zend_extension *extension) /* {{{ */
3711{
3712    llist_dtor_func_t dtor;
3713
3714    assert(extension);
3715    dtor = zend_extensions.dtor; /* avoid dtor */
3716    zend_extensions.dtor = NULL;
3717    zend_llist_del_element(&zend_extensions, extension, xc_ptr_compare_func);
3718    zend_extensions.dtor = dtor;
3719    return SUCCESS;
3720}
3721/* }}} */
3722static int xc_config_hash(xc_hash_t *p, char *name, char *default_value) /* {{{ */
3723{
3724    int bits, size;
3725    char *value;
3726
3727    if (cfg_get_string(name, &value) != SUCCESS) {
3728        value = default_value;
3729    }
3730
3731    p->size = zend_atoi(value, strlen(value));
3732    for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {
3733        /* empty body */
3734    }
3735    p->size = size;
3736    p->bits = bits;
3737    p->mask = size - 1;
3738
3739    return SUCCESS;
3740}
3741/* }}} */
3742static int xc_config_long(zend_ulong *p, char *name, char *default_value) /* {{{ */
3743{
3744    char *value;
3745
3746    if (cfg_get_string(name, &value) != SUCCESS) {
3747        value = default_value;
3748    }
3749
3750    *p = zend_atol(value, strlen(value));
3751    return SUCCESS;
3752}
3753/* }}} */
3754/* {{{ PHP_MINIT_FUNCTION(xcache) */
3755static PHP_MINIT_FUNCTION(xcache)
3756{
3757    char *env;
3758    zend_extension *ext;
3759    zend_llist_position lpos;
3760
3761    xc_module_gotup = 1;
3762    if (!xc_zend_extension_gotup) {
3763        xc_zend_extension_register(&zend_extension_entry, 0);
3764        xc_zend_extension_startup(&zend_extension_entry);
3765        xc_zend_extension_faked = 1;
3766    }
3767
3768    ext = zend_get_extension("Zend Optimizer");
3769    if (ext) {
3770        /* zend_optimizer.optimization_level>0 is not compatible with other cacher, disabling */
3771        ext->op_array_handler = NULL;
3772    }
3773    /* cache if there's an op_array_ctor */
3774    for (ext = zend_llist_get_first_ex(&zend_extensions, &lpos);
3775            ext;
3776            ext = zend_llist_get_next_ex(&zend_extensions, &lpos)) {
3777        if (ext->op_array_ctor) {
3778            xc_have_op_array_ctor = 1;
3779            break;
3780        }
3781    }
3782
3783
3784#ifndef PHP_GINIT
3785    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
3786#endif
3787    REGISTER_INI_ENTRIES();
3788
3789    xc_config_long(&xc_php_size,       "xcache.size",        "0");
3790    xc_config_hash(&xc_php_hcache,     "xcache.count",       "1");
3791    xc_config_hash(&xc_php_hentry,     "xcache.slots",      "8K");
3792
3793    xc_config_long(&xc_var_size,       "xcache.var_size",    "0");
3794    xc_config_hash(&xc_var_hcache,     "xcache.var_count",   "1");
3795    xc_config_hash(&xc_var_hentry,     "xcache.var_slots",  "8K");
3796
3797    if (strcmp(sapi_module.name, "cli") == 0) {
3798        if ((env = getenv("XCACHE_TEST")) != NULL) {
3799            xc_test = atoi(env);
3800        }
3801        if (!xc_test) {
3802            /* disable cache for cli except for testing */
3803            xc_php_size = xc_var_size = 0;
3804        }
3805    }
3806
3807    if (xc_php_size <= 0) {
3808        xc_php_size = xc_php_hcache.size = 0;
3809    }
3810    if (xc_var_size <= 0) {
3811        xc_var_size = xc_var_hcache.size = 0;
3812    }
3813
3814    if (xc_coredump_dir && xc_coredump_dir[0]) {
3815        xcache_init_crash_handler();
3816    }
3817
3818    xc_init_constant(module_number TSRMLS_CC);
3819    xc_shm_init_modules();
3820
3821    if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {
3822        if (xc_init(module_number TSRMLS_CC) != SUCCESS) {
3823            zend_error(E_ERROR, "XCache: Cannot init");
3824            goto err_init;
3825        }
3826        xc_initized = 1;
3827        xc_init_time = time(NULL);
3828#ifdef PHP_WIN32
3829        xc_init_instance_id = GetCurrentProcessId();
3830#else
3831        xc_init_instance_id = getpid();
3832#endif
3833#ifdef ZTS
3834        xc_init_instance_subid = tsrm_thread_id();
3835#endif
3836    }
3837
3838    xc_util_init(module_number TSRMLS_CC);
3839#ifdef HAVE_XCACHE_COVERAGER
3840    xc_coverager_init(module_number TSRMLS_CC);
3841#endif
3842
3843    return SUCCESS;
3844
3845err_init:
3846    return FAILURE;
3847}
3848/* }}} */
3849/* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */
3850static PHP_MSHUTDOWN_FUNCTION(xcache)
3851{
3852    if (xc_initized) {
3853        xc_destroy();
3854    }
3855    if (xc_mmap_path) {
3856        pefree(xc_mmap_path, 1);
3857        xc_mmap_path = NULL;
3858    }
3859    if (xc_shm_scheme) {
3860        pefree(xc_shm_scheme, 1);
3861        xc_shm_scheme = NULL;
3862    }
3863
3864#ifdef HAVE_XCACHE_COVERAGER
3865    xc_coverager_destroy();
3866#endif
3867    xc_util_destroy();
3868
3869    if (xc_coredump_dir && xc_coredump_dir[0]) {
3870        xcache_restore_crash_handler();
3871    }
3872    if (xc_coredump_dir) {
3873        pefree(xc_coredump_dir, 1);
3874        xc_coredump_dir = NULL;
3875    }
3876#ifndef PHP_GINIT
3877#   ifdef ZTS
3878    ts_free_id(xcache_globals_id);
3879#   else
3880    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
3881#   endif
3882#endif
3883
3884    if (xc_zend_extension_faked) {
3885        zend_extension *ext = zend_get_extension(XCACHE_NAME);
3886        if (ext) {
3887            if (ext->shutdown) {
3888                ext->shutdown(ext);
3889            }
3890            xc_zend_remove_extension(ext);
3891        }
3892    }
3893    UNREGISTER_INI_ENTRIES();
3894
3895    xc_module_gotup = 0;
3896    xc_zend_extension_gotup = 0;
3897    xc_zend_extension_faked = 0;
3898
3899    return SUCCESS;
3900}
3901/* }}} */
3902/* {{{ PHP_RINIT_FUNCTION(xcache) */
3903static PHP_RINIT_FUNCTION(xcache)
3904{
3905    xc_request_init(TSRMLS_C);
3906    return SUCCESS;
3907}
3908/* }}} */
3909/* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */
3910#ifndef ZEND_ENGINE_2
3911static PHP_RSHUTDOWN_FUNCTION(xcache)
3912#else
3913static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache)
3914#endif
3915{
3916#ifdef ZEND_ENGINE_2
3917    TSRMLS_FETCH();
3918#endif
3919
3920    xc_request_shutdown(TSRMLS_C);
3921    return SUCCESS;
3922}
3923/* }}} */
3924/* {{{ module dependencies */
3925#if ZEND_MODULE_API_NO >= 20050922
3926static zend_module_dep xcache_module_deps[] = {
3927    ZEND_MOD_REQUIRED("standard")
3928    ZEND_MOD_CONFLICTS("apc")
3929    ZEND_MOD_CONFLICTS("eAccelerator")
3930    ZEND_MOD_CONFLICTS("Turck MMCache")
3931    {NULL, NULL, NULL}
3932};
3933#endif
3934/* }}} */ 
3935/* {{{ module definition structure */
3936
3937zend_module_entry xcache_module_entry = {
3938#if ZEND_MODULE_API_NO >= 20050922
3939    STANDARD_MODULE_HEADER_EX,
3940    NULL,
3941    xcache_module_deps,
3942#else
3943    STANDARD_MODULE_HEADER,
3944#endif
3945    XCACHE_NAME,
3946    xcache_functions,
3947    PHP_MINIT(xcache),
3948    PHP_MSHUTDOWN(xcache),
3949    PHP_RINIT(xcache),
3950#ifndef ZEND_ENGINE_2
3951    PHP_RSHUTDOWN(xcache),
3952#else
3953    NULL,
3954#endif
3955    PHP_MINFO(xcache),
3956    XCACHE_VERSION,
3957#ifdef PHP_GINIT
3958    PHP_MODULE_GLOBALS(xcache),
3959    PHP_GINIT(xcache),
3960    PHP_GSHUTDOWN(xcache),
3961#endif
3962#ifdef ZEND_ENGINE_2
3963    ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),
3964#else
3965    NULL,
3966    NULL,
3967#endif
3968    STANDARD_MODULE_PROPERTIES_EX
3969};
3970
3971#ifdef COMPILE_DL_XCACHE
3972ZEND_GET_MODULE(xcache)
3973#endif
3974/* }}} */
3975static startup_func_t xc_last_ext_startup;
3976static int xc_zend_startup_last(zend_extension *extension) /* {{{ */
3977{
3978    /* restore */
3979    extension->startup = xc_last_ext_startup;
3980    if (extension->startup) {
3981        if (extension->startup(extension) != SUCCESS) {
3982            return FAILURE;
3983        }
3984    }
3985    assert(xc_llist_zend_extension);
3986    xc_llist_prepend(&zend_extensions, xc_llist_zend_extension);
3987    if (!xc_module_gotup) {
3988        return zend_startup_module(&xcache_module_entry);
3989    }
3990    return SUCCESS;
3991}
3992/* }}} */
3993ZEND_DLEXPORT int xcache_zend_startup(zend_extension *extension) /* {{{ */
3994{
3995    xc_zend_extension_gotup = 1;
3996
3997    if (!origin_compile_file) {
3998        origin_compile_file = zend_compile_file;
3999        zend_compile_file = xc_check_initial_compile_file;
4000    }
4001
4002    if (zend_llist_count(&zend_extensions) > 1) {
4003        zend_llist_position lpos;
4004        zend_extension *ext;
4005
4006        xc_llist_zend_extension = xc_llist_get_element_by_zend_extension(&zend_extensions, XCACHE_NAME);
4007        xc_llist_unlink(&zend_extensions, xc_llist_zend_extension);
4008
4009        ext = (zend_extension *) zend_llist_get_last_ex(&zend_extensions, &lpos);
4010        assert(ext && ext != (zend_extension *) xc_llist_zend_extension->data);
4011        xc_last_ext_startup = ext->startup;
4012        ext->startup = xc_zend_startup_last;
4013    }
4014    else if (!xc_module_gotup) {
4015        return zend_startup_module(&xcache_module_entry);
4016    }
4017    return SUCCESS;
4018}
4019/* }}} */
4020ZEND_DLEXPORT void xcache_zend_shutdown(zend_extension *extension) /* {{{ */
4021{
4022    /* empty */
4023}
4024/* }}} */
4025ZEND_DLEXPORT void xcache_statement_handler(zend_op_array *op_array) /* {{{ */
4026{
4027#ifdef HAVE_XCACHE_COVERAGER
4028    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
4029#endif
4030}
4031/* }}} */
4032ZEND_DLEXPORT void xcache_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
4033{
4034#if 0
4035    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
4036#endif
4037}
4038/* }}} */
4039ZEND_DLEXPORT void xcache_fcall_end_handler(zend_op_array *op_array) /* {{{ */
4040{
4041#if 0
4042    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
4043#endif
4044}
4045/* }}} */
4046/* {{{ zend extension definition structure */
4047ZEND_DLEXPORT zend_extension zend_extension_entry = {
4048    XCACHE_NAME,
4049    XCACHE_VERSION,
4050    XCACHE_AUTHOR,
4051    XCACHE_URL,
4052    XCACHE_COPYRIGHT,
4053    xcache_zend_startup,
4054    xcache_zend_shutdown,
4055    NULL,           /* activate_func_t */
4056    NULL,           /* deactivate_func_t */
4057    NULL,           /* message_handler_func_t */
4058#ifdef HAVE_XCACHE_OPTIMIZER
4059    xc_optimizer_op_array_handler,
4060#else
4061    NULL,           /* op_array_handler_func_t */
4062#endif
4063    xcache_statement_handler,
4064    xcache_fcall_begin_handler,
4065    xcache_fcall_end_handler,
4066    NULL,           /* op_array_ctor_func_t */
4067    NULL,           /* op_array_dtor_func_t */
4068    STANDARD_ZEND_EXTENSION_PROPERTIES
4069};
4070
4071#ifndef ZEND_EXT_API
4072#   define ZEND_EXT_API ZEND_DLEXPORT
4073#endif
4074#if COMPILE_DL_XCACHE
4075ZEND_EXTENSION();
4076#endif
4077/* }}} */
Note: See TracBrowser for help on using the repository browser.