source: trunk/xcache.c @ 961

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

revert opt out of included_files handling. still required by require()/include(). make it work for new sandbox handling

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