Changeset 1040 in svn
- Timestamp:
- 2012-07-25T03:14:09Z (6 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Makefile.frag.deps
r1026 r1040 1 1 $(XCACHE_INCLUDES_I) $(builddir)/includes.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h 2 2 $(builddir)/mod_assembler/xc_assembler.lo: 3 $(builddir)/mod_cacher/xc_cacher.lo: $(srcdir)/mod_cacher/xc_cacher.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(XCACHE_PROC_H) $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/util/xc_trace.h $(srcdir)/util/xc_vector.h $(srcdir)/util/xc_align.h 3 4 $(builddir)/mod_coverager/xc_coverager.lo: $(srcdir)/mod_coverager/xc_coverager.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h 4 5 $(builddir)/mod_decoder/xc_decoder.lo: 5 $(builddir)/mod_disassembler/xc_disassembler.lo: $(srcdir)/mod_disassembler/xc_disassembler.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_ utils.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_compatibility.h $(XCACHE_PROC_H)6 $(builddir)/mod_disassembler/xc_disassembler.lo: $(srcdir)/mod_disassembler/xc_disassembler.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_compatibility.h $(XCACHE_PROC_H) 6 7 $(builddir)/mod_encoder/xc_encoder.lo: 7 8 $(builddir)/mod_optimizer/xc_optimizer.lo: $(srcdir)/mod_optimizer/xc_optimizer.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/util/xc_stack.h $(srcdir)/util/xc_trace.h $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h 8 9 $(builddir)/util/xc_stack.lo: $(srcdir)/util/xc_trace.h $(srcdir)/util/xc_stack.h 9 10 $(builddir)/util/xc_trace.lo: $(srcdir)/util/xc_trace.h 10 $(builddir)/xcache.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h $( XCACHE_PROC_H) $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_opcode_spec.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/util/xc_align.h $(srcdir)/util/xc_vector.h $(srcdir)/util/xc_trace.h $(srcdir)/util/xc_foreachcoresig.h11 $(builddir)/xcache.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache/xc_ini.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_opcode_spec.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/util/xc_foreachcoresig.h 11 12 $(builddir)/xcache/xc_compatibility.lo: $(srcdir)/xcache/xc_compatibility.h 12 13 $(builddir)/xcache/xc_const_string.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_const_string_opcodes_php5.4.h 13 14 $(builddir)/xcache/xc_extension.lo: $(srcdir)/xcache/xc_extension.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/util/xc_trace.h 14 15 $(builddir)/xcache/xc_ini.lo: $(srcdir)/xcache/xc_ini.h 15 $(builddir)/xcache/xc_lock.lo: $(srcdir)/xcache/xc_lock.h 16 $(builddir)/xcache/xc_lock.lo: $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h 16 17 $(builddir)/xcache/xc_malloc.lo: $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/util/xc_align.h 17 18 $(builddir)/xcache/xc_mem.lo: $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/util/xc_align.h $(srcdir)/util/xc_trace.h 18 19 $(builddir)/xcache/xc_opcode_spec.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_opcode_spec.h $(srcdir)/xcache/xc_const_string.h $(srcdir)/xcache/xc_opcode_spec_def.h 19 20 $(builddir)/xcache/xc_processor.lo: $(XCACHE_PROC_C) $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/util/xc_align.h $(srcdir)/xcache/xc_const_string.h $(XCACHE_PROC_H) $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h 20 $(builddir)/xcache/xc_sandbox.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache /xc_compatibility.h $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h21 $(builddir)/xcache/xc_sandbox.lo: $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_sandbox.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache_globals.h $(srcdir)/util/xc_stack.h 21 22 $(builddir)/xcache/xc_shm.lo: $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h 22 23 $(builddir)/xcache/xc_shm_mmap.lo: $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_mem.h $(srcdir)/xcache/xc_utils.h $(srcdir)/xcache.h $(srcdir)/xcache/xc_shm.h $(srcdir)/xcache/xc_lock.h $(srcdir)/xcache/xc_compatibility.h $(srcdir)/xcache/xc_compatibility.h -
trunk/config.m4
r1026 r1040 47 47 xcache_sources="$xcache_sources xcache/$i" 48 48 done 49 for i in \ 50 xc_cacher.c \ 51 ; do 52 xcache_sources="$xcache_sources mod_cacher/$i" 53 done 49 54 XCACHE_MODULES="cacher" 55 AC_DEFINE([HAVE_XCACHE_CACHER], 1, [Define to enable XCache cacher]) 50 56 XCACHE_MODULE([optimizer], [optimizer ], [XCACHE_OPTIMIZER], [(N/A)]) 51 57 XCACHE_MODULE([coverager], [coverager ], [XCACHE_COVERAGER], [Enable code coverage dumper, useful for testing php scripts]) -
trunk/config.w32
r1026 r1040 32 32 xc_utils.c \ 33 33 ", "xcache"); 34 ADD_SOURCES(configure_module_dirname + "/xcache", " \ 35 xc_cacher.c \ 36 ", "xcache"); 34 37 35 38 // {{{ add sources on enabled … … 42 45 43 46 var XCACHE_MODULES = "cacher"; 47 AC_DEFINE("HAVE_XCACHE_CACHER", 1, "Define for XCache: cacher") 44 48 var options = ["optimizer", 45 49 "coverager", -
trunk/xcache.c
r1030 r1040 1 2 #if 03 #define XCACHE_DEBUG4 #endif5 6 #if 07 #define SHOW_DPRINT8 #endif9 10 1 /* {{{ macros */ 11 2 #include <stdlib.h> … … 16 7 17 8 #include "xcache.h" 18 #ifdef ZEND_ENGINE_2_119 #include "ext/date/php_date.h"20 #endif21 9 22 10 #ifdef HAVE_XCACHE_OPTIMIZER 23 11 # include "mod_optimizer/xc_optimizer.h" 24 12 #endif 13 #ifdef HAVE_XCACHE_CACHER 14 # include "mod_cacher/xc_cacher.h" 15 #endif 25 16 #ifdef HAVE_XCACHE_COVERAGER 26 17 # include "mod_coverager/xc_coverager.h" … … 31 22 32 23 #include "xcache_globals.h" 33 #include "xc_processor.h"34 24 #include "xcache/xc_extension.h" 35 25 #include "xcache/xc_ini.h" … … 37 27 #include "xcache/xc_opcode_spec.h" 38 28 #include "xcache/xc_utils.h" 39 #include "xcache/xc_sandbox.h"40 #include "util/xc_align.h"41 29 #include "util/xc_stack.h" 42 #include "util/xc_vector.h"43 #include "util/xc_trace.h"44 30 45 31 #include "php.h" 46 32 #include "ext/standard/info.h" 47 #include "ext/standard/md5.h"48 #include "ext/standard/php_math.h"49 33 #include "ext/standard/php_string.h" 50 #include "SAPI.h"51 52 #define VAR_ENTRY_EXPIRED(pentry) ((pentry)->ttl && XG(request_time) > (pentry)->ctime + (time_t) (pentry)->ttl)53 #define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)54 #define LOCK(x) xc_lock((x)->lck)55 #define UNLOCK(x) xc_unlock((x)->lck)56 57 #define ENTER_LOCK_EX(x) \58 xc_lock((x)->lck); \59 zend_try { \60 do61 #define LEAVE_LOCK_EX(x) \62 while (0); \63 } zend_catch { \64 catched = 1; \65 } zend_end_try(); \66 xc_unlock((x)->lck)67 68 #define ENTER_LOCK(x) do { \69 int catched = 0; \70 ENTER_LOCK_EX(x)71 #define LEAVE_LOCK(x) \72 LEAVE_LOCK_EX(x); \73 if (catched) { \74 zend_bailout(); \75 } \76 } while(0)77 78 34 /* }}} */ 79 35 80 36 /* {{{ globals */ 81 static char *xc_shm_scheme = NULL;82 static char *xc_mmap_path = NULL;83 37 static char *xc_coredump_dir = NULL; 84 38 static zend_bool xc_disable_on_crash = 0; 85 39 86 static xc_hash_t xc_php_hcache = { 0, 0, 0 };87 static xc_hash_t xc_php_hentry = { 0, 0, 0 };88 static xc_hash_t xc_var_hcache = { 0, 0, 0 };89 static xc_hash_t xc_var_hentry = { 0, 0, 0 };90 91 static zend_ulong xc_php_ttl = 0;92 static zend_ulong xc_var_maxttl = 0;93 94 enum { xc_deletes_gc_interval = 120 };95 static zend_ulong xc_php_gc_interval = 0;96 static zend_ulong xc_var_gc_interval = 0;97 98 /* total size */99 static zend_ulong xc_php_size = 0;100 static zend_ulong xc_var_size = 0;101 102 static xc_shm_t *xc_shm = NULL;103 static xc_cache_t **xc_php_caches = NULL;104 static xc_cache_t **xc_var_caches = NULL;105 106 static zend_bool xc_initized = 0;107 static time_t xc_init_time = 0;108 static long unsigned xc_init_instance_id = 0;109 #ifdef ZTS110 static long unsigned xc_init_instance_subid = 0;111 #endif112 static zend_compile_file_t *origin_compile_file = NULL;113 40 static zend_compile_file_t *old_compile_file = NULL; 114 41 static zend_llist_element *xc_llist_zend_extension = NULL; 115 42 116 static zend_bool xc_test = 0; 117 static zend_bool xc_readonly_protection = 0; 118 119 zend_bool xc_have_op_array_ctor = 0; 43 zend_bool xc_test = 0; 120 44 121 45 ZEND_DECLARE_MODULE_GLOBALS(xcache) 122 46 123 typedef enum { XC_TYPE_PHP, XC_TYPE_VAR } xc_entry_type_t; 124 /* }}} */ 125 126 /* any function in *_unlocked is only safe be called within locked (single thread access) area */ 127 128 static void xc_php_add_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php) /* {{{ */ 129 { 130 xc_entry_data_php_t **head = &(cache->phps[php->hvalue]); 131 php->next = *head; 132 *head = php; 133 cache->phps_count ++; 134 } 135 /* }}} */ 136 static xc_entry_data_php_t *xc_php_store_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */ 137 { 138 xc_entry_data_php_t *stored_php; 139 140 php->hits = 0; 141 php->refcount = 0; 142 stored_php = xc_processor_store_xc_entry_data_php_t(cache, php TSRMLS_CC); 143 if (stored_php) { 144 xc_php_add_unlocked(cache, stored_php); 145 return stored_php; 146 } 147 else { 148 cache->ooms ++; 149 return NULL; 150 } 151 } 152 /* }}} */ 153 static xc_entry_data_php_t *xc_php_find_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */ 154 { 155 xc_entry_data_php_t *p; 156 for (p = cache->phps[php->hvalue]; p; p = (xc_entry_data_php_t *) p->next) { 157 if (memcmp(&php->md5.digest, &p->md5.digest, sizeof(php->md5.digest)) == 0) { 158 p->hits ++; 159 return p; 160 } 161 } 162 return NULL; 163 } 164 /* }}} */ 165 static void xc_php_free_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php) /* {{{ */ 166 { 167 cache->mem->handlers->free(cache->mem, (xc_entry_data_php_t *)php); 168 } 169 /* }}} */ 170 static void xc_php_addref_unlocked(xc_entry_data_php_t *php) /* {{{ */ 171 { 172 php->refcount ++; 173 } 174 /* }}} */ 175 static void xc_php_release_unlocked(xc_cache_t *cache, xc_entry_data_php_t *php) /* {{{ */ 176 { 177 if (-- php->refcount == 0) { 178 xc_entry_data_php_t **pp = &(cache->phps[php->hvalue]); 179 xc_entry_data_php_t *p; 180 for (p = *pp; p; pp = &(p->next), p = p->next) { 181 if (memcmp(&php->md5.digest, &p->md5.digest, sizeof(php->md5.digest)) == 0) { 182 /* unlink */ 183 *pp = p->next; 184 xc_php_free_unlocked(cache, php); 185 return; 186 } 187 } 188 assert(0); 189 } 190 } 191 /* }}} */ 192 193 static inline int xc_entry_equal_unlocked(xc_entry_type_t type, const xc_entry_t *entry1, const xc_entry_t *entry2 TSRMLS_DC) /* {{{ */ 194 { 195 /* this function isn't required but can be in unlocked */ 196 switch (type) { 197 case XC_TYPE_PHP: 198 { 199 const xc_entry_php_t *php_entry1 = (const xc_entry_php_t *) entry1; 200 const xc_entry_php_t *php_entry2 = (const xc_entry_php_t *) entry2; 201 if (php_entry1->file_inode && php_entry2->file_inode) { 202 zend_bool inodeIsSame = php_entry1->file_inode == php_entry2->file_inode 203 && php_entry1->file_device == php_entry2->file_device; 204 if (XG(experimental)) { 205 /* new experimental behavior: quick check by inode, first */ 206 if (!inodeIsSame) { 207 return 0; 208 } 209 210 /* and then opened_path compare */ 211 } 212 else { 213 /* old behavior: inode check only */ 214 return inodeIsSame; 215 } 216 } 217 } 218 219 assert(IS_ABSOLUTE_PATH(entry1->name.str.val, entry1->name.str.len)); 220 assert(IS_ABSOLUTE_PATH(entry2->name.str.val, entry2->name.str.len)); 221 222 return entry1->name.str.len == entry2->name.str.len 223 && memcmp(entry1->name.str.val, entry2->name.str.val, entry1->name.str.len + 1) == 0; 224 225 case XC_TYPE_VAR: 226 #ifdef IS_UNICODE 227 if (entry1->name_type != entry2->name_type) { 228 return 0; 229 } 230 231 if (entry1->name_type == IS_UNICODE) { 232 return entry1->name.ustr.len == entry2->name.ustr.len 233 && memcmp(entry1->name.ustr.val, entry2->name.ustr.val, (entry1->name.ustr.len + 1) * sizeof(UChar)) == 0; 234 } 235 #endif 236 return entry1->name.str.len == entry2->name.str.len 237 && memcmp(entry1->name.str.val, entry2->name.str.val, entry1->name.str.len + 1) == 0; 238 break; 239 240 default: 241 assert(0); 242 } 243 return 0; 244 } 245 /* }}} */ 246 static inline int xc_entry_has_prefix_unlocked(xc_entry_type_t type, xc_entry_t *entry, zval *prefix) /* {{{ */ 247 { 248 /* this function isn't required but can be in unlocked */ 249 250 #ifdef IS_UNICODE 251 if (entry->name_type != prefix->type) { 252 return 0; 253 } 254 255 if (entry->name_type == IS_UNICODE) { 256 if (entry->name.ustr.len < Z_USTRLEN_P(prefix)) { 257 return 0; 258 } 259 return memcmp(entry->name.ustr.val, Z_USTRVAL_P(prefix), Z_USTRLEN_P(prefix) * sizeof(UChar)) == 0; 260 } 261 #endif 262 if (prefix->type != IS_STRING) { 263 return 0; 264 } 265 266 if (entry->name.str.len < Z_STRLEN_P(prefix)) { 267 return 0; 268 } 269 270 return memcmp(entry->name.str.val, Z_STRVAL_P(prefix), Z_STRLEN_P(prefix)) == 0; 271 } 272 /* }}} */ 273 static void xc_entry_add_unlocked(xc_cache_t *cache, xc_hash_value_t entryslotid, xc_entry_t *entry) /* {{{ */ 274 { 275 xc_entry_t **head = &(cache->entries[entryslotid]); 276 entry->next = *head; 277 *head = entry; 278 cache->entries_count ++; 279 } 280 /* }}} */ 281 static 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) /* {{{ */ 282 { 283 xc_entry_t *stored_entry; 284 285 entry->hits = 0; 286 entry->ctime = XG(request_time); 287 entry->atime = XG(request_time); 288 stored_entry = type == XC_TYPE_PHP 289 ? (xc_entry_t *) xc_processor_store_xc_entry_php_t(cache, (xc_entry_php_t *) entry TSRMLS_CC) 290 : (xc_entry_t *) xc_processor_store_xc_entry_var_t(cache, (xc_entry_var_t *) entry TSRMLS_CC); 291 if (stored_entry) { 292 xc_entry_add_unlocked(cache, entryslotid, stored_entry); 293 ++cache->updates; 294 return stored_entry; 295 } 296 else { 297 cache->ooms ++; 298 return NULL; 299 } 300 } 301 /* }}} */ 302 static 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) /* {{{ */ 303 { 304 return (xc_entry_php_t *) xc_entry_store_unlocked(XC_TYPE_PHP, cache, entryslotid, (xc_entry_t *) entry_php TSRMLS_CC); 305 } 306 /* }}} */ 307 static 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) /* {{{ */ 308 { 309 return (xc_entry_var_t *) xc_entry_store_unlocked(XC_TYPE_VAR, cache, entryslotid, (xc_entry_t *) entry_var TSRMLS_CC); 310 } 311 /* }}} */ 312 static void xc_entry_free_real_unlocked(xc_entry_type_t type, xc_cache_t *cache, volatile xc_entry_t *entry) /* {{{ */ 313 { 314 if (type == XC_TYPE_PHP) { 315 xc_php_release_unlocked(cache, ((xc_entry_php_t *) entry)->php); 316 } 317 cache->mem->handlers->free(cache->mem, (xc_entry_t *)entry); 318 } 319 /* }}} */ 320 static void xc_entry_free_unlocked(xc_entry_type_t type, xc_cache_t *cache, xc_entry_t *entry TSRMLS_DC) /* {{{ */ 321 { 322 cache->entries_count --; 323 if ((type == XC_TYPE_PHP ? ((xc_entry_php_t *) entry)->refcount : 0) == 0) { 324 xc_entry_free_real_unlocked(type, cache, entry); 325 } 326 else { 327 entry->next = cache->deletes; 328 cache->deletes = entry; 329 entry->dtime = XG(request_time); 330 cache->deletes_count ++; 331 } 332 return; 333 } 334 /* }}} */ 335 static 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) /* {{{ */ 336 { 337 xc_entry_t **pp = &(cache->entries[entryslotid]); 338 xc_entry_t *p; 339 for (p = *pp; p; pp = &(p->next), p = p->next) { 340 if (xc_entry_equal_unlocked(type, entry, p TSRMLS_CC)) { 341 /* unlink */ 342 *pp = p->next; 343 xc_entry_free_unlocked(type, cache, entry TSRMLS_CC); 344 return; 345 } 346 } 347 assert(0); 348 } 349 /* }}} */ 350 static 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) /* {{{ */ 351 { 352 xc_entry_t *p; 353 for (p = cache->entries[entryslotid]; p; p = p->next) { 354 if (xc_entry_equal_unlocked(type, entry, p TSRMLS_CC)) { 355 zend_bool fresh; 356 switch (type) { 357 case XC_TYPE_PHP: 358 { 359 xc_entry_php_t *p_php = (xc_entry_php_t *) p; 360 xc_entry_php_t *entry_php = (xc_entry_php_t *) entry; 361 fresh = p_php->file_mtime == entry_php->file_mtime && p_php->file_size == entry_php->file_size; 362 } 363 break; 364 365 case XC_TYPE_VAR: 366 { 367 fresh = !VAR_ENTRY_EXPIRED(p); 368 } 369 break; 370 371 default: 372 assert(0); 373 } 374 375 if (fresh) { 376 p->hits ++; 377 p->atime = XG(request_time); 378 return p; 379 } 380 381 xc_entry_remove_unlocked(type, cache, entryslotid, p TSRMLS_CC); 382 return NULL; 383 } 384 } 385 return NULL; 386 } 387 /* }}} */ 388 static void xc_entry_hold_php_unlocked(xc_cache_t *cache, xc_entry_php_t *entry TSRMLS_DC) /* {{{ */ 389 { 390 TRACE("hold %d:%s", entry->file_inode, entry->entry.name.str.val); 391 entry->refcount ++; 392 xc_stack_push(&XG(php_holds)[cache->cacheid], (void *)entry); 393 } 394 /* }}} */ 395 static inline zend_uint advance_wrapped(zend_uint val, zend_uint count) /* {{{ */ 396 { 397 if (val + 1 >= count) { 398 return 0; 399 } 400 return val + 1; 401 } 402 /* }}} */ 403 static void xc_counters_inc(time_t *curtime, zend_uint *curslot, time_t period, zend_ulong *counters, zend_uint count TSRMLS_DC) /* {{{ */ 404 { 405 time_t n = XG(request_time) / period; 406 if (*curtime != n) { 407 zend_uint target_slot = n % count; 408 if (n - *curtime > period) { 409 memset(counters, 0, sizeof(counters[0]) * count); 410 } 411 else { 412 zend_uint slot; 413 for (slot = advance_wrapped(*curslot, count); 414 slot != target_slot; 415 slot = advance_wrapped(slot, count)) { 416 counters[slot] = 0; 417 } 418 counters[target_slot] = 0; 419 } 420 *curtime = n; 421 *curslot = target_slot; 422 } 423 counters[*curslot] ++; 424 } 425 /* }}} */ 426 static void xc_cache_hit_unlocked(xc_cache_t *cache TSRMLS_DC) /* {{{ */ 427 { 428 cache->hits ++; 429 430 xc_counters_inc(&cache->hits_by_hour_cur_time 431 , &cache->hits_by_hour_cur_slot, 60 * 60 432 , cache->hits_by_hour 433 , sizeof(cache->hits_by_hour) / sizeof(cache->hits_by_hour[0]) 434 TSRMLS_CC); 435 436 xc_counters_inc(&cache->hits_by_second_cur_time 437 , &cache->hits_by_second_cur_slot 438 , 1 439 , cache->hits_by_second 440 , sizeof(cache->hits_by_second) / sizeof(cache->hits_by_second[0]) 441 TSRMLS_CC); 442 } 443 /* }}} */ 444 445 /* helper function that loop through each entry */ 446 #define XC_ENTRY_APPLY_FUNC(name) zend_bool name(xc_entry_t *entry TSRMLS_DC) 447 typedef XC_ENTRY_APPLY_FUNC((*cache_apply_unlocked_func_t)); 448 static void xc_entry_apply_unlocked(xc_entry_type_t type, xc_cache_t *cache, cache_apply_unlocked_func_t apply_func TSRMLS_DC) /* {{{ */ 449 { 450 xc_entry_t *p, **pp; 451 int i, c; 452 453 for (i = 0, c = cache->hentry->size; i < c; i ++) { 454 pp = &(cache->entries[i]); 455 for (p = *pp; p; p = *pp) { 456 if (apply_func(p TSRMLS_CC)) { 457 /* unlink */ 458 *pp = p->next; 459 xc_entry_free_unlocked(type, cache, p TSRMLS_CC); 460 } 461 else { 462 pp = &(p->next); 463 } 464 } 465 } 466 } 467 /* }}} */ 468 469 #define XC_CACHE_APPLY_FUNC(name) void name(xc_cache_t *cache TSRMLS_DC) 470 /* call graph: 471 * xc_gc_expires_php -> xc_gc_expires_one -> xc_entry_apply_unlocked -> xc_gc_expires_php_entry_unlocked 472 * xc_gc_expires_var -> xc_gc_expires_one -> xc_entry_apply_unlocked -> xc_gc_expires_var_entry_unlocked 473 */ 474 static XC_ENTRY_APPLY_FUNC(xc_gc_expires_php_entry_unlocked) /* {{{ */ 475 { 476 TRACE("ttl %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) entry->atime, xc_php_ttl); 477 if (XG(request_time) > entry->atime + (time_t) xc_php_ttl) { 478 return 1; 479 } 480 return 0; 481 } 482 /* }}} */ 483 static XC_ENTRY_APPLY_FUNC(xc_gc_expires_var_entry_unlocked) /* {{{ */ 484 { 485 if (VAR_ENTRY_EXPIRED(entry)) { 486 return 1; 487 } 488 return 0; 489 } 490 /* }}} */ 491 static 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) /* {{{ */ 492 { 493 TRACE("interval %lu, %lu %lu", (zend_ulong) XG(request_time), (zend_ulong) cache->last_gc_expires, gc_interval); 494 if (XG(request_time) >= cache->last_gc_expires + (time_t) gc_interval) { 495 ENTER_LOCK(cache) { 496 if (XG(request_time) >= cache->last_gc_expires + (time_t) gc_interval) { 497 cache->last_gc_expires = XG(request_time); 498 xc_entry_apply_unlocked(type, cache, apply_func TSRMLS_CC); 499 } 500 } LEAVE_LOCK(cache); 501 } 502 } 503 /* }}} */ 504 static void xc_gc_expires_php(TSRMLS_D) /* {{{ */ 505 { 506 int i, c; 507 508 if (!xc_php_ttl || !xc_php_gc_interval || !xc_php_caches) { 509 return; 510 } 511 512 for (i = 0, c = xc_php_hcache.size; i < c; i ++) { 513 xc_gc_expires_one(XC_TYPE_PHP, xc_php_caches[i], xc_php_gc_interval, xc_gc_expires_php_entry_unlocked TSRMLS_CC); 514 } 515 } 516 /* }}} */ 517 static void xc_gc_expires_var(TSRMLS_D) /* {{{ */ 518 { 519 int i, c; 520 521 if (!xc_var_gc_interval || !xc_var_caches) { 522 return; 523 } 524 525 for (i = 0, c = xc_var_hcache.size; i < c; i ++) { 526 xc_gc_expires_one(XC_TYPE_VAR, xc_var_caches[i], xc_var_gc_interval, xc_gc_expires_var_entry_unlocked TSRMLS_CC); 527 } 528 } 529 /* }}} */ 530 531 static XC_CACHE_APPLY_FUNC(xc_gc_delete_unlocked) /* {{{ */ 532 { 533 xc_entry_t *p, **pp; 534 535 pp = &cache->deletes; 536 for (p = *pp; p; p = *pp) { 537 xc_entry_php_t *entry = (xc_entry_php_t *) p; 538 if (XG(request_time) - p->dtime > 3600) { 539 entry->refcount = 0; 540 /* issue warning here */ 541 } 542 if (entry->refcount == 0) { 543 /* unlink */ 544 *pp = p->next; 545 cache->deletes_count --; 546 xc_entry_free_real_unlocked(XC_TYPE_PHP, cache, p); 547 } 548 else { 549 pp = &(p->next); 550 } 551 } 552 } 553 /* }}} */ 554 static XC_CACHE_APPLY_FUNC(xc_gc_deletes_one) /* {{{ */ 555 { 556 if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) { 557 ENTER_LOCK(cache) { 558 if (cache->deletes && XG(request_time) - cache->last_gc_deletes > xc_deletes_gc_interval) { 559 cache->last_gc_deletes = XG(request_time); 560 xc_gc_delete_unlocked(cache TSRMLS_CC); 561 } 562 } LEAVE_LOCK(cache); 563 } 564 } 565 /* }}} */ 566 static void xc_gc_deletes(TSRMLS_D) /* {{{ */ 567 { 568 int i, c; 569 570 if (xc_php_caches) { 571 for (i = 0, c = xc_php_hcache.size; i < c; i ++) { 572 xc_gc_deletes_one(xc_php_caches[i] TSRMLS_CC); 573 } 574 } 575 576 if (xc_var_caches) { 577 for (i = 0, c = xc_var_hcache.size; i < c; i ++) { 578 xc_gc_deletes_one(xc_var_caches[i] TSRMLS_CC); 579 } 580 } 581 } 582 /* }}} */ 583 584 /* helper functions for user functions */ 585 static void xc_fillinfo_unlocked(int cachetype, xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */ 586 { 587 zval *blocks, *hits; 588 size_t i; 589 const xc_block_t *b; 590 #ifndef NDEBUG 591 xc_memsize_t avail = 0; 592 #endif 593 xc_mem_t *mem = cache->mem; 594 const xc_mem_handlers_t *handlers = mem->handlers; 595 zend_ulong interval; 596 if (cachetype == XC_TYPE_PHP) { 597 interval = xc_php_ttl ? xc_php_gc_interval : 0; 598 } 599 else { 600 interval = xc_var_gc_interval; 601 } 602 603 add_assoc_long_ex(return_value, ZEND_STRS("slots"), cache->hentry->size); 604 add_assoc_long_ex(return_value, ZEND_STRS("compiling"), cache->compiling); 605 add_assoc_long_ex(return_value, ZEND_STRS("updates"), cache->updates); 606 add_assoc_long_ex(return_value, ZEND_STRS("misses"), cache->updates); /* deprecated */ 607 add_assoc_long_ex(return_value, ZEND_STRS("hits"), cache->hits); 608 add_assoc_long_ex(return_value, ZEND_STRS("clogs"), cache->clogs); 609 add_assoc_long_ex(return_value, ZEND_STRS("ooms"), cache->ooms); 610 add_assoc_long_ex(return_value, ZEND_STRS("errors"), cache->errors); 611 612 add_assoc_long_ex(return_value, ZEND_STRS("cached"), cache->entries_count); 613 add_assoc_long_ex(return_value, ZEND_STRS("deleted"), cache->deletes_count); 614 if (interval) { 615 time_t gc = (cache->last_gc_expires + interval) - XG(request_time); 616 add_assoc_long_ex(return_value, ZEND_STRS("gc"), gc > 0 ? gc : 0); 617 } 618 else { 619 add_assoc_null_ex(return_value, ZEND_STRS("gc")); 620 } 621 MAKE_STD_ZVAL(hits); 622 array_init(hits); 623 for (i = 0; i < sizeof(cache->hits_by_hour) / sizeof(cache->hits_by_hour[0]); i ++) { 624 add_next_index_long(hits, (long) cache->hits_by_hour[i]); 625 } 626 add_assoc_zval_ex(return_value, ZEND_STRS("hits_by_hour"), hits); 627 628 MAKE_STD_ZVAL(hits); 629 array_init(hits); 630 for (i = 0; i < sizeof(cache->hits_by_second) / sizeof(cache->hits_by_second[0]); i ++) { 631 add_next_index_long(hits, (long) cache->hits_by_second[i]); 632 } 633 add_assoc_zval_ex(return_value, ZEND_STRS("hits_by_second"), hits); 634 635 MAKE_STD_ZVAL(blocks); 636 array_init(blocks); 637 638 add_assoc_long_ex(return_value, ZEND_STRS("size"), handlers->size(mem)); 639 add_assoc_long_ex(return_value, ZEND_STRS("avail"), handlers->avail(mem)); 640 add_assoc_bool_ex(return_value, ZEND_STRS("can_readonly"), xc_readonly_protection); 641 642 for (b = handlers->freeblock_first(mem); b; b = handlers->freeblock_next(b)) { 643 zval *bi; 644 645 MAKE_STD_ZVAL(bi); 646 array_init(bi); 647 648 add_assoc_long_ex(bi, ZEND_STRS("size"), handlers->block_size(b)); 649 add_assoc_long_ex(bi, ZEND_STRS("offset"), handlers->block_offset(mem, b)); 650 add_next_index_zval(blocks, bi); 651 #ifndef NDEBUG 652 avail += handlers->block_size(b); 653 #endif 654 } 655 add_assoc_zval_ex(return_value, ZEND_STRS("free_blocks"), blocks); 656 #ifndef NDEBUG 657 assert(avail == handlers->avail(mem)); 658 #endif 659 } 660 /* }}} */ 661 static 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) /* {{{ */ 662 { 663 zval* ei; 664 const xc_entry_data_php_t *php; 665 666 ALLOC_INIT_ZVAL(ei); 667 array_init(ei); 668 669 add_assoc_long_ex(ei, ZEND_STRS("hits"), entry->hits); 670 add_assoc_long_ex(ei, ZEND_STRS("ctime"), entry->ctime); 671 add_assoc_long_ex(ei, ZEND_STRS("atime"), entry->atime); 672 add_assoc_long_ex(ei, ZEND_STRS("hvalue"), entryslotid); 673 if (del) { 674 add_assoc_long_ex(ei, ZEND_STRS("dtime"), entry->dtime); 675 } 676 #ifdef IS_UNICODE 677 do { 678 zval *zv; 679 ALLOC_INIT_ZVAL(zv); 680 switch (entry->name_type) { 681 case IS_UNICODE: 682 ZVAL_UNICODEL(zv, entry->name.ustr.val, entry->name.ustr.len, 1); 683 break; 684 case IS_STRING: 685 ZVAL_STRINGL(zv, entry->name.str.val, entry->name.str.len, 1); 686 break; 687 default: 688 assert(0); 689 } 690 zv->type = entry->name_type; 691 add_assoc_zval_ex(ei, ZEND_STRS("name"), zv); 692 } while (0); 693 #else 694 add_assoc_stringl_ex(ei, ZEND_STRS("name"), entry->name.str.val, entry->name.str.len, 1); 695 #endif 696 switch (type) { 697 case XC_TYPE_PHP: { 698 xc_entry_php_t *entry_php = (xc_entry_php_t *) entry; 699 php = entry_php->php; 700 add_assoc_long_ex(ei, ZEND_STRS("size"), entry->size + php->size); 701 add_assoc_long_ex(ei, ZEND_STRS("refcount"), entry_php->refcount); 702 add_assoc_long_ex(ei, ZEND_STRS("phprefcount"), php->refcount); 703 add_assoc_long_ex(ei, ZEND_STRS("file_mtime"), entry_php->file_mtime); 704 add_assoc_long_ex(ei, ZEND_STRS("file_size"), entry_php->file_size); 705 add_assoc_long_ex(ei, ZEND_STRS("file_device"), entry_php->file_device); 706 add_assoc_long_ex(ei, ZEND_STRS("file_inode"), entry_php->file_inode); 707 708 #ifdef HAVE_XCACHE_CONSTANT 709 add_assoc_long_ex(ei, ZEND_STRS("constinfo_cnt"), php->constinfo_cnt); 710 #endif 711 add_assoc_long_ex(ei, ZEND_STRS("function_cnt"), php->funcinfo_cnt); 712 add_assoc_long_ex(ei, ZEND_STRS("class_cnt"), php->classinfo_cnt); 713 #ifdef ZEND_ENGINE_2_1 714 add_assoc_long_ex(ei, ZEND_STRS("autoglobal_cnt"),php->autoglobal_cnt); 715 #endif 716 break; 717 } 718 719 case XC_TYPE_VAR: 720 add_assoc_long_ex(ei, ZEND_STRS("refcount"), 0); /* for BC only */ 721 add_assoc_long_ex(ei, ZEND_STRS("size"), entry->size); 722 break; 723 724 default: 725 assert(0); 726 } 727 728 add_next_index_zval(list, ei); 729 } 730 /* }}} */ 731 static void xc_filllist_unlocked(xc_entry_type_t type, xc_cache_t *cache, zval *return_value TSRMLS_DC) /* {{{ */ 732 { 733 zval* list; 734 int i, c; 735 xc_entry_t *e; 736 737 ALLOC_INIT_ZVAL(list); 738 array_init(list); 739 740 for (i = 0, c = cache->hentry->size; i < c; i ++) { 741 for (e = cache->entries[i]; e; e = e->next) { 742 xc_fillentry_unlocked(type, e, i, 0, list TSRMLS_CC); 743 } 744 } 745 add_assoc_zval(return_value, "cache_list", list); 746 747 ALLOC_INIT_ZVAL(list); 748 array_init(list); 749 for (e = cache->deletes; e; e = e->next) { 750 xc_fillentry_unlocked(XC_TYPE_PHP, e, 0, 1, list TSRMLS_CC); 751 } 752 add_assoc_zval(return_value, "deleted_list", list); 753 } 754 /* }}} */ 755 756 static zend_op_array *xc_entry_install(xc_entry_php_t *entry_php TSRMLS_DC) /* {{{ */ 757 { 758 zend_uint i; 759 xc_entry_data_php_t *p = entry_php->php; 760 zend_op_array *old_active_op_array = CG(active_op_array); 761 #ifndef ZEND_ENGINE_2 762 ALLOCA_FLAG(use_heap) 763 /* new ptr which is stored inside CG(class_table) */ 764 xc_cest_t **new_cest_ptrs = (xc_cest_t **)my_do_alloca(sizeof(xc_cest_t*) * p->classinfo_cnt, use_heap); 765 #endif 766 767 CG(active_op_array) = p->op_array; 768 769 #ifdef HAVE_XCACHE_CONSTANT 770 /* install constant */ 771 for (i = 0; i < p->constinfo_cnt; i ++) { 772 xc_constinfo_t *ci = &p->constinfos[i]; 773 xc_install_constant(entry_php->entry.name.str.val, &ci->constant, 774 UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC); 775 } 776 #endif 777 778 /* install function */ 779 for (i = 0; i < p->funcinfo_cnt; i ++) { 780 xc_funcinfo_t *fi = &p->funcinfos[i]; 781 xc_install_function(entry_php->entry.name.str.val, &fi->func, 782 UNISW(0, fi->type), fi->key, fi->key_size, fi->h TSRMLS_CC); 783 } 784 785 /* install class */ 786 for (i = 0; i < p->classinfo_cnt; i ++) { 787 xc_classinfo_t *ci = &p->classinfos[i]; 788 #ifndef ZEND_ENGINE_2 789 zend_class_entry *ce = CestToCePtr(ci->cest); 790 /* fix pointer to the be which inside class_table */ 791 if (ce->parent) { 792 zend_uint class_idx = (/* class_num */ (int) (long) ce->parent) - 1; 793 assert(class_idx < i); 794 ci->cest.parent = new_cest_ptrs[class_idx]; 795 } 796 new_cest_ptrs[i] = 797 #endif 798 #ifdef ZEND_COMPILE_DELAYED_BINDING 799 xc_install_class(entry_php->entry.name.str.val, &ci->cest, -1, 800 UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC); 801 #else 802 xc_install_class(entry_php->entry.name.str.val, &ci->cest, ci->oplineno, 803 UNISW(0, ci->type), ci->key, ci->key_size, ci->h TSRMLS_CC); 804 #endif 805 } 806 807 #ifdef ZEND_ENGINE_2_1 808 /* trigger auto_globals jit */ 809 for (i = 0; i < p->autoglobal_cnt; i ++) { 810 xc_autoglobal_t *aginfo = &p->autoglobals[i]; 811 zend_u_is_auto_global(aginfo->type, aginfo->key, aginfo->key_len TSRMLS_CC); 812 } 813 #endif 814 #ifdef XCACHE_ERROR_CACHING 815 /* restore trigger errors */ 816 for (i = 0; i < p->compilererror_cnt; i ++) { 817 xc_compilererror_t *error = &p->compilererrors[i]; 818 CG(zend_lineno) = error->lineno; 819 zend_error(error->type, "%s", error->error); 820 } 821 CG(zend_lineno) = 0; 822 #endif 823 824 i = 1; 825 #ifndef ZEND_ENGINE_2_2 826 zend_hash_add(&EG(included_files), entry_php->entry.name.str.val, entry_php->entry.name.str.len+1, (void *)&i, sizeof(int), NULL); 827 #endif 828 829 #ifndef ZEND_ENGINE_2 830 my_free_alloca(new_cest_ptrs, use_heap); 831 #endif 832 CG(active_op_array) = old_active_op_array; 833 return p->op_array; 834 } 835 /* }}} */ 836 837 static inline void xc_entry_unholds_real(xc_stack_t *holds, xc_cache_t **caches, int cachecount TSRMLS_DC) /* {{{ */ 838 { 839 int i; 840 xc_stack_t *s; 841 xc_cache_t *cache; 842 xc_entry_php_t *entry_php; 843 844 for (i = 0; i < cachecount; i ++) { 845 s = &holds[i]; 846 TRACE("holded %d items", xc_stack_count(s)); 847 if (xc_stack_count(s)) { 848 cache = caches[i]; 849 ENTER_LOCK(cache) { 850 while (xc_stack_count(s)) { 851 entry_php = (xc_entry_php_t *) xc_stack_pop(s); 852 TRACE("unhold %d:%s", entry_php->file_inode, entry_php->entry.name.str.val); 853 assert(entry_php->refcount > 0); 854 --entry_php->refcount; 855 } 856 } LEAVE_LOCK(cache); 857 } 858 } 859 } 860 /* }}} */ 861 static void xc_entry_unholds(TSRMLS_D) /* {{{ */ 862 { 863 if (xc_php_caches) { 864 xc_entry_unholds_real(XG(php_holds), xc_php_caches, xc_php_hcache.size TSRMLS_CC); 865 } 866 867 if (xc_var_caches) { 868 xc_entry_unholds_real(XG(var_holds), xc_var_caches, xc_var_hcache.size TSRMLS_CC); 869 } 870 } 871 /* }}} */ 872 873 #define HASH(i) (i) 874 #define HASH_ZSTR_L(t, s, l) HASH(zend_u_inline_hash_func((t), (s), ((l) + 1) * sizeof(UChar))) 875 #define HASH_STR_S(s, l) HASH(zend_inline_hash_func((char *) (s), (l))) 876 #define HASH_STR_L(s, l) HASH_STR_S((s), (l) + 1) 877 #define HASH_STR(s) HASH_STR_L((s), strlen((s)) + 1) 878 #define HASH_NUM(n) HASH(n) 879 static inline xc_hash_value_t xc_hash_fold(xc_hash_value_t hvalue, const xc_hash_t *hasher) /* {{{ fold hash bits as needed */ 880 { 881 xc_hash_value_t folded = 0; 882 while (hvalue) { 883 folded ^= (hvalue & hasher->mask); 884 hvalue >>= hasher->bits; 885 } 886 return folded; 887 } 888 /* }}} */ 889 static inline xc_hash_value_t xc_entry_hash_name(xc_entry_t *entry TSRMLS_DC) /* {{{ */ 890 { 891 return UNISW(NOTHING, UG(unicode) ? HASH_ZSTR_L(entry->name_type, entry->name.uni.val, entry->name.uni.len) :) 892 HASH_STR_L(entry->name.str.val, entry->name.str.len); 893 } 894 /* }}} */ 895 #define xc_entry_hash_var xc_entry_hash_name 896 static void xc_entry_free_key_php(xc_entry_php_t *entry_php TSRMLS_DC) /* {{{ */ 897 { 898 #define X_FREE(var) do {\ 899 if (entry_php->var) { \ 900 efree(entry_php->var); \ 901 } \ 902 } while (0) 903 X_FREE(dirpath); 904 #ifdef IS_UNICODE 905 X_FREE(ufilepath); 906 X_FREE(udirpath); 907 #endif 908 909 #undef X_FREE 910 } 911 /* }}} */ 912 static char *xc_expand_url(const char *filepath, char *real_path TSRMLS_DC) /* {{{ */ 913 { 914 if (strstr(filepath, "://") != NULL) { 915 size_t filepath_len = strlen(filepath); 916 size_t copy_len = filepath_len > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : filepath_len; 917 memcpy(real_path, filepath, filepath_len); 918 real_path[copy_len] = '\0'; 919 return real_path; 920 } 921 return expand_filepath(filepath, real_path TSRMLS_CC); 922 } 923 /* }}} */ 924 925 #define XC_RESOLVE_PATH_CHECKER(name) zend_bool name(const char *filepath, size_t filepath_len, void *data TSRMLS_DC) 926 typedef XC_RESOLVE_PATH_CHECKER((*xc_resolve_path_checker_func_t)); 927 static zend_bool xc_resolve_path(const char *filepath, char *path_buffer, xc_resolve_path_checker_func_t checker_func, void *data TSRMLS_DC) /* {{{ */ 928 { 929 char *paths, *path; 930 char *tokbuf; 931 size_t path_buffer_len; 932 int size; 933 char tokens[] = { DEFAULT_DIR_SEPARATOR, '\0' }; 934 int ret; 935 ALLOCA_FLAG(use_heap) 936 937 #if 0 938 if ((*filepath == '.' && 939 (IS_SLASH(filepath[1]) || 940 ((filepath[1] == '.') && IS_SLASH(filepath[2])))) || 941 IS_ABSOLUTE_PATH(filepath, strlen(filepath)) || 942 !path || 943 !*path) { 944 945 if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) { 946 ret = 1; 947 } 948 else { 949 ret = FAILURE; 950 } 951 goto finish; 952 } 953 #endif 954 955 size = strlen(PG(include_path)) + 1; 956 paths = (char *)my_do_alloca(size, use_heap); 957 memcpy(paths, PG(include_path), size); 958 959 for (path = php_strtok_r(paths, tokens, &tokbuf); path; path = php_strtok_r(NULL, tokens, &tokbuf)) { 960 path_buffer_len = snprintf(path_buffer, MAXPATHLEN, "%s/%s", path, filepath); 961 if (path_buffer_len < MAXPATHLEN - 1) { 962 if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) { 963 ret = 1; 964 goto finish; 965 } 966 } 967 } 968 969 /* fall back to current directory */ 970 if (zend_is_executing(TSRMLS_C)) { 971 const char *executed_filename = zend_get_executed_filename(TSRMLS_C); 972 if (executed_filename && executed_filename[0] && executed_filename[0] != '[') { 973 size_t filename_len = strlen(filepath); 974 size_t dirname_len; 975 976 for (dirname_len = strlen(executed_filename) - 1; dirname_len > 0; --dirname_len) { 977 if (IS_SLASH(executed_filename[dirname_len])) { 978 if (dirname_len + filename_len < MAXPATHLEN - 1) { 979 ++dirname_len; /* include tailing slash */ 980 memcpy(path_buffer, executed_filename, dirname_len); 981 memcpy(path_buffer + dirname_len, filepath, filename_len); 982 path_buffer_len = dirname_len + filename_len; 983 path_buffer[path_buffer_len] = '\0'; 984 if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) { 985 ret = 1; 986 goto finish; 987 } 988 } 989 break; 990 } 991 } 992 } 993 } 994 995 ret = 0; 996 997 finish: 998 my_free_alloca(paths, use_heap); 999 1000 return ret; 1001 } 1002 /* }}} */ 1003 #ifndef ZEND_ENGINE_2_3 1004 static XC_RESOLVE_PATH_CHECKER(xc_stat_file) /* {{{ */ 1005 { 1006 return VCWD_STAT(filepath, (struct stat *) data) == 0 ? 1 : 0; 1007 } 1008 /* }}} */ 1009 static int xc_resolve_path_stat(const char *filepath, char *path_buffer, struct stat *pbuf TSRMLS_DC) /* {{{ */ 1010 { 1011 return xc_resolve_path(filepath, path_buffer, xc_stat_file, (void *) pbuf TSRMLS_CC) 1012 ? SUCCESS 1013 : FAILURE; 1014 } 1015 /* }}} */ 1016 #endif 1017 typedef struct xc_compiler_t { /* {{{ */ 1018 /* XCache cached compile state */ 1019 const char *filename; 1020 size_t filename_len; 1021 const char *opened_path; 1022 char opened_path_buffer[MAXPATHLEN]; 1023 1024 xc_entry_hash_t entry_hash; 1025 xc_entry_php_t new_entry; 1026 xc_entry_data_php_t new_php; 1027 } xc_compiler_t; 1028 /* }}} */ 1029 typedef struct xc_entry_resolve_path_data_t { /* {{{ */ 1030 xc_compiler_t *compiler; 1031 xc_entry_php_t **stored_entry; 1032 } xc_entry_resolve_path_data_t; 1033 /* }}} */ 1034 static XC_RESOLVE_PATH_CHECKER(xc_entry_resolve_path_func_unlocked) /* {{{ */ 1035 { 1036 xc_entry_resolve_path_data_t *entry_resolve_path_data = (xc_entry_resolve_path_data_t *) data; 1037 xc_compiler_t *compiler = entry_resolve_path_data->compiler; 1038 1039 compiler->new_entry.entry.name.str.val = xc_expand_url(filepath, compiler->opened_path_buffer TSRMLS_CC); 1040 compiler->new_entry.entry.name.str.len = strlen(compiler->new_entry.entry.name.str.val); 1041 1042 *entry_resolve_path_data->stored_entry = (xc_entry_php_t *) xc_entry_find_unlocked( 1043 XC_TYPE_PHP 1044 , xc_php_caches[compiler->entry_hash.cacheid] 1045 , compiler->entry_hash.entryslotid 1046 , (xc_entry_t *) &compiler->new_entry 1047 TSRMLS_CC); 1048 1049 return *entry_resolve_path_data->stored_entry ? 1 : 0; 1050 } 1051 /* }}} */ 1052 static int xc_entry_resolve_path_unlocked(xc_compiler_t *compiler, const char *filepath, xc_entry_php_t **stored_entry TSRMLS_DC) /* {{{ */ 1053 { 1054 char path_buffer[MAXPATHLEN]; 1055 xc_entry_resolve_path_data_t entry_resolve_path_data; 1056 entry_resolve_path_data.compiler = compiler; 1057 entry_resolve_path_data.stored_entry = stored_entry; 1058 1059 return xc_resolve_path(filepath, path_buffer, xc_entry_resolve_path_func_unlocked, (void *) &entry_resolve_path_data TSRMLS_CC) 1060 ? SUCCESS 1061 : FAILURE; 1062 } 1063 /* }}} */ 1064 static int xc_entry_php_quick_resolve_opened_path(xc_compiler_t *compiler, struct stat *statbuf TSRMLS_DC) /* {{{ */ 1065 { 1066 if (strcmp(SG(request_info).path_translated, compiler->filename) == 0) { 1067 /* sapi has already done this stat() for us */ 1068 if (statbuf) { 1069 struct stat *sapi_stat = sapi_get_stat(TSRMLS_C); 1070 if (!sapi_stat) { 1071 goto giveupsapistat; 1072 } 1073 *statbuf = *sapi_stat; 1074 } 1075 1076 compiler->opened_path = xc_expand_url(compiler->filename, compiler->opened_path_buffer TSRMLS_CC); 1077 return SUCCESS; 1078 } 1079 giveupsapistat: 1080 1081 /* absolute path */ 1082 if (IS_ABSOLUTE_PATH(compiler->filename, strlen(compiler->filename))) { 1083 if (statbuf && VCWD_STAT(compiler->filename, statbuf) != 0) { 1084 return FAILURE; 1085 } 1086 compiler->opened_path = xc_expand_url(compiler->filename, compiler->opened_path_buffer TSRMLS_CC); 1087 return SUCCESS; 1088 } 1089 1090 /* relative path */ 1091 if (*compiler->filename == '.' && (IS_SLASH(compiler->filename[1]) || compiler->filename[1] == '.')) { 1092 const char *ptr = compiler->filename + 1; 1093 if (*ptr == '.') { 1094 while (*(++ptr) == '.'); 1095 if (!IS_SLASH(*ptr)) { 1096 return FAILURE; 1097 } 1098 } 1099 1100 if (statbuf && VCWD_STAT(compiler->filename, statbuf) != 0) { 1101 return FAILURE; 1102 } 1103 1104 compiler->opened_path = xc_expand_url(compiler->filename, compiler->opened_path_buffer TSRMLS_CC); 1105 return SUCCESS; 1106 } 1107 1108 return FAILURE; 1109 } 1110 /* }}} */ 1111 static int xc_entry_php_resolve_opened_path(xc_compiler_t *compiler, struct stat *statbuf TSRMLS_DC) /* {{{ */ 1112 { 1113 if (xc_entry_php_quick_resolve_opened_path(compiler, statbuf TSRMLS_CC) == SUCCESS) { 1114 /* opened_path resolved */ 1115 return SUCCESS; 1116 } 1117 /* fall back to real stat call */ 1118 else { 1119 #ifdef ZEND_ENGINE_2_3 1120 char *opened_path = php_resolve_path(compiler->filename, compiler->filename_len, PG(include_path) TSRMLS_CC); 1121 if (opened_path) { 1122 strcpy(compiler->opened_path_buffer, opened_path); 1123 efree(opened_path); 1124 compiler->opened_path = compiler->opened_path_buffer; 1125 if (!statbuf || VCWD_STAT(compiler->opened_path, statbuf) == 0) { 1126 return SUCCESS; 1127 } 1128 } 1129 #else 1130 char path_buffer[MAXPATHLEN]; 1131 if (xc_resolve_path_stat(compiler->filename, path_buffer, statbuf TSRMLS_CC) == SUCCESS) { 1132 compiler->opened_path = xc_expand_url(path_buffer, compiler->opened_path_buffer TSRMLS_CC); 1133 return SUCCESS; 1134 } 1135 #endif 1136 } 1137 return FAILURE; 1138 } 1139 /* }}} */ 1140 static int xc_entry_php_init_key(xc_compiler_t *compiler TSRMLS_DC) /* {{{ */ 1141 { 1142 if (XG(stat)) { 1143 struct stat buf; 1144 time_t delta; 1145 1146 if (compiler->opened_path) { 1147 if (VCWD_STAT(compiler->opened_path, &buf) != 0) { 1148 return FAILURE; 1149 } 1150 } 1151 else { 1152 if (xc_entry_php_resolve_opened_path(compiler, &buf TSRMLS_CC) != SUCCESS) { 1153 return FAILURE; 1154 } 1155 } 1156 1157 delta = XG(request_time) - buf.st_mtime; 1158 if (abs(delta) < 2 && !xc_test) { 1159 return FAILURE; 1160 } 1161 1162 compiler->new_entry.file_mtime = buf.st_mtime; 1163 compiler->new_entry.file_size = buf.st_size; 1164 compiler->new_entry.file_device = buf.st_dev; 1165 compiler->new_entry.file_inode = buf.st_ino; 1166 } 1167 else { 1168 xc_entry_php_quick_resolve_opened_path(compiler, NULL TSRMLS_CC); 1169 1170 compiler->new_entry.file_mtime = 0; 1171 compiler->new_entry.file_size = 0; 1172 compiler->new_entry.file_device = 0; 1173 compiler->new_entry.file_inode = 0; 1174 } 1175 1176 { 1177 xc_hash_value_t basename_hash_value; 1178 if (xc_php_hcache.size > 1 1179 || !compiler->new_entry.file_inode) { 1180 const char *filename_end = compiler->filename + compiler->filename_len; 1181 const char *basename = filename_end - 1; 1182 1183 /* scan till out of basename part */ 1184 while (basename >= compiler->filename && !IS_SLASH(*basename)) { 1185 --basename; 1186 } 1187 /* get back to basename */ 1188 ++basename; 1189 1190 basename_hash_value = HASH_STR_L(basename, filename_end - basename); 1191 } 1192 1193 compiler->entry_hash.cacheid = xc_php_hcache.size > 1 ? xc_hash_fold(basename_hash_value, &xc_php_hcache) : 0; 1194 compiler->entry_hash.entryslotid = xc_hash_fold( 1195 compiler->new_entry.file_inode 1196 ? (xc_hash_value_t) HASH(compiler->new_entry.file_device + compiler->new_entry.file_inode) 1197 : basename_hash_value 1198 , &xc_php_hentry); 1199 } 1200 1201 compiler->new_entry.filepath = NULL; 1202 compiler->new_entry.dirpath = NULL; 1203 #ifdef IS_UNICODE 1204 compiler->new_entry.ufilepath = NULL; 1205 compiler->new_entry.udirpath = NULL; 1206 #endif 1207 1208 return SUCCESS; 1209 } 1210 /* }}} */ 1211 static inline xc_hash_value_t xc_php_hash_md5(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */ 1212 { 1213 return HASH_STR_S(php->md5.digest, sizeof(php->md5.digest)); 1214 } 1215 /* }}} */ 1216 static int xc_entry_data_php_init_md5(xc_cache_t *cache, xc_compiler_t *compiler TSRMLS_DC) /* {{{ */ 1217 { 1218 unsigned char buf[1024]; 1219 PHP_MD5_CTX context; 1220 int n; 1221 php_stream *stream; 1222 ulong old_rsid = EG(regular_list).nNextFreeElement; 1223 1224 stream = php_stream_open_wrapper((char *) compiler->filename, "rb", USE_PATH | REPORT_ERRORS | ENFORCE_SAFE_MODE | STREAM_DISABLE_OPEN_BASEDIR, NULL); 1225 if (!stream) { 1226 return FAILURE; 1227 } 1228 1229 PHP_MD5Init(&context); 1230 while ((n = php_stream_read(stream, (char *) buf, sizeof(buf))) > 0) { 1231 PHP_MD5Update(&context, buf, n); 1232 } 1233 PHP_MD5Final((unsigned char *) compiler->new_php.md5.digest, &context); 1234 1235 php_stream_close(stream); 1236 if (EG(regular_list).nNextFreeElement == old_rsid + 1) { 1237 EG(regular_list).nNextFreeElement = old_rsid; 1238 } 1239 1240 if (n < 0) { 1241 return FAILURE; 1242 } 1243 1244 compiler->new_php.hvalue = (xc_php_hash_md5(&compiler->new_php TSRMLS_CC) & cache->hphp->mask); 1245 #ifdef XCACHE_DEBUG 1246 { 1247 char md5str[33]; 1248 make_digest(md5str, (unsigned char *) compiler->new_php.md5.digest); 1249 TRACE("md5 %s", md5str); 1250 } 1251 #endif 1252 1253 return SUCCESS; 1254 } 1255 /* }}} */ 1256 static void xc_entry_php_init(xc_entry_php_t *entry_php, const char *filepath TSRMLS_DC) /* {{{*/ 1257 { 1258 entry_php->filepath = ZEND_24((char *), NOTHING) filepath; 1259 entry_php->filepath_len = strlen(entry_php->filepath); 1260 entry_php->dirpath = estrndup(entry_php->filepath, entry_php->filepath_len); 1261 entry_php->dirpath_len = zend_dirname(entry_php->dirpath, entry_php->filepath_len); 1262 #ifdef IS_UNICODE 1263 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); 1264 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); 1265 #endif 1266 } 1267 /* }}} */ 1268 #ifndef ZEND_COMPILE_DELAYED_BINDING 1269 static void xc_cache_early_binding_class_cb(zend_op *opline, int oplineno, void *data TSRMLS_DC) /* {{{ */ 1270 { 1271 char *class_name; 1272 zend_uint i; 1273 int class_len; 1274 xc_cest_t cest; 1275 xc_entry_data_php_t *php = (xc_entry_data_php_t *) data; 1276 1277 class_name = Z_OP_CONSTANT(opline->op1).value.str.val; 1278 class_len = Z_OP_CONSTANT(opline->op1).value.str.len; 1279 if (zend_hash_find(CG(class_table), class_name, class_len, (void **) &cest) == FAILURE) { 1280 assert(0); 1281 } 1282 TRACE("got ZEND_DECLARE_INHERITED_CLASS: %s", class_name + 1); 1283 /* let's see which class */ 1284 for (i = 0; i < php->classinfo_cnt; i ++) { 1285 if (memcmp(ZSTR_S(php->classinfos[i].key), class_name, class_len) == 0) { 1286 php->classinfos[i].oplineno = oplineno; 1287 php->have_early_binding = 1; 1288 break; 1289 } 1290 } 1291 1292 if (i == php->classinfo_cnt) { 1293 assert(0); 1294 } 1295 } 1296 /* }}} */ 1297 #endif 1298 1299 /* {{{ Constant Usage */ 1300 #ifdef ZEND_ENGINE_2_4 1301 # define xcache_literal_is_dir 1 1302 # define xcache_literal_is_file 2 1303 #else 1304 # define xcache_op1_is_file 1 1305 # define xcache_op1_is_dir 2 1306 # define xcache_op2_is_file 4 1307 # define xcache_op2_is_dir 8 1308 #endif 1309 typedef struct { 1310 zend_bool filepath_used; 1311 zend_bool dirpath_used; 1312 zend_bool ufilepath_used; 1313 zend_bool udirpath_used; 1314 } xc_const_usage_t; 1315 /* }}} */ 1316 static 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) /* {{{ */ 1317 { 1318 #ifdef ZEND_ENGINE_2_4 1319 int literalindex; 1320 #else 1321 zend_uint oplinenum; 1322 #endif 1323 xc_vector_t details; 1324 1325 xc_vector_init(xc_op_array_info_detail_t, &details); 1326 1327 #define XCACHE_ANALYZE_LITERAL(type) \ 1328 if (zend_binary_strcmp(Z_STRVAL(literal->constant), Z_STRLEN(literal->constant), compiler->new_entry.type##path, compiler->new_entry.type##path_len) == 0) { \ 1329 usage->type##path_used = 1; \ 1330 literalinfo |= xcache_##literal##_is_##type; \ 1331 } 1332 1333 #define XCACHE_U_ANALYZE_LITERAL(type) \ 1334 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) { \ 1335 usage->u##type##path_used = 1; \ 1336 literalinfo |= xcache_##literal##_is_##type; \ 1337 } 1338 1339 #define XCACHE_ANALYZE_OP(type, op) \ 1340 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) { \ 1341 usage->type##path_used = 1; \ 1342 oplineinfo |= xcache_##op##_is_##type; \ 1343 } 1344 1345 #define XCACHE_U_ANALYZE_OP(type, op) \ 1346 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) { \ 1347 usage->u##type##path_used = 1; \ 1348 oplineinfo |= xcache_##op##_is_##type; \ 1349 } 1350 1351 #ifdef ZEND_ENGINE_2_4 1352 for (literalindex = 0; literalindex < op_array->last_literal; literalindex++) { 1353 zend_literal *literal = &op_array->literals[literalindex]; 1354 zend_uint literalinfo = 0; 1355 if (Z_TYPE(literal->constant) == IS_STRING) { 1356 XCACHE_ANALYZE_LITERAL(file) 1357 else XCACHE_ANALYZE_LITERAL(dir) 1358 } 1359 #ifdef IS_UNICODE 1360 else if (Z_TYPE(literal->constant) == IS_UNICODE) { 1361 XCACHE_U_ANALYZE_LITERAL(file) 1362 else XCACHE_U_ANALYZE_LITERAL(dir) 1363 } 1364 #endif 1365 if (literalinfo) { 1366 xc_op_array_info_detail_t detail; 1367 detail.index = literalindex; 1368 detail.info = literalinfo; 1369 xc_vector_add(xc_op_array_info_detail_t, &details, detail); 1370 } 1371 } 1372 1373 op_array_info->literalinfo_cnt = details.cnt; 1374 op_array_info->literalinfos = xc_vector_detach(xc_op_array_info_detail_t, &details); 1375 #else /* ZEND_ENGINE_2_4 */ 1376 for (oplinenum = 0; oplinenum < op_array->last; oplinenum++) { 1377 zend_op *opline = &op_array->opcodes[oplinenum]; 1378 zend_uint oplineinfo = 0; 1379 if (Z_OP_TYPE(opline->op1) == IS_CONST) { 1380 if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) { 1381 XCACHE_ANALYZE_OP(file, op1) 1382 else XCACHE_ANALYZE_OP(dir, op1) 1383 } 1384 #ifdef IS_UNICODE 1385 else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) { 1386 XCACHE_U_ANALYZE_OP(file, op1) 1387 else XCACHE_U_ANALYZE_OP(dir, op1) 1388 } 1389 #endif 1390 } 1391 1392 if (Z_OP_TYPE(opline->op2) == IS_CONST) { 1393 if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) { 1394 XCACHE_ANALYZE_OP(file, op2) 1395 else XCACHE_ANALYZE_OP(dir, op2) 1396 } 1397 #ifdef IS_UNICODE 1398 else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) { 1399 XCACHE_U_ANALYZE_OP(file, op2) 1400 else XCACHE_U_ANALYZE_OP(dir, op2) 1401 } 1402 #endif 1403 } 1404 1405 if (oplineinfo) { 1406 xc_op_array_info_detail_t detail; 1407 detail.index = oplinenum; 1408 detail.info = oplineinfo; 1409 xc_vector_add(xc_op_array_info_detail_t, &details, detail); 1410 } 1411 } 1412 1413 op_array_info->oplineinfo_cnt = details.cnt; 1414 op_array_info->oplineinfos = xc_vector_detach(xc_op_array_info_detail_t, &details); 1415 #endif /* ZEND_ENGINE_2_4 */ 1416 xc_vector_free(xc_op_array_info_detail_t, &details); 1417 } 1418 /* }}} */ 1419 void 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) /* {{{ */ 1420 { 1421 #ifdef ZEND_ENGINE_2_4 1422 zend_uint literalinfoindex; 1423 1424 for (literalinfoindex = 0; literalinfoindex < op_array_info->literalinfo_cnt; ++literalinfoindex) { 1425 int literalindex = op_array_info->literalinfos[literalinfoindex].index; 1426 int literalinfo = op_array_info->literalinfos[literalinfoindex].info; 1427 zend_literal *literal = &op_array->literals[literalindex]; 1428 if ((literalinfo & xcache_literal_is_file)) { 1429 if (!shallow_copy) { 1430 efree(Z_STRVAL(literal->constant)); 1431 } 1432 if (Z_TYPE(literal->constant) == IS_STRING) { 1433 assert(entry_php->filepath); 1434 ZVAL_STRINGL(&literal->constant, entry_php->filepath, entry_php->filepath_len, !shallow_copy); 1435 TRACE("restored literal constant: %s", entry_php->filepath); 1436 } 1437 #ifdef IS_UNICODE 1438 else if (Z_TYPE(literal->constant) == IS_UNICODE) { 1439 assert(entry_php->ufilepath); 1440 ZVAL_UNICODEL(&literal->constant, entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy); 1441 } 1442 #endif 1443 else { 1444 assert(0); 1445 } 1446 } 1447 else if ((literalinfo & xcache_literal_is_dir)) { 1448 if (!shallow_copy) { 1449 efree(Z_STRVAL(literal->constant)); 1450 } 1451 if (Z_TYPE(literal->constant) == IS_STRING) { 1452 assert(entry_php->dirpath); 1453 TRACE("restored literal constant: %s", entry_php->dirpath); 1454 ZVAL_STRINGL(&literal->constant, entry_php->dirpath, entry_php->dirpath_len, !shallow_copy); 1455 } 1456 #ifdef IS_UNICODE 1457 else if (Z_TYPE(literal->constant) == IS_UNICODE) { 1458 assert(!entry_php->udirpath); 1459 ZVAL_UNICODEL(&literal->constant, entry_php->udirpath, entry_php->udirpath_len, !shallow_copy); 1460 } 1461 #endif 1462 else { 1463 assert(0); 1464 } 1465 } 1466 } 1467 #else /* ZEND_ENGINE_2_4 */ 1468 zend_uint oplinenum; 1469 1470 for (oplinenum = 0; oplinenum < op_array_info->oplineinfo_cnt; ++oplinenum) { 1471 int oplineindex = op_array_info->oplineinfos[oplinenum].index; 1472 int oplineinfo = op_array_info->oplineinfos[oplinenum].info; 1473 zend_op *opline = &op_array->opcodes[oplineindex]; 1474 if ((oplineinfo & xcache_op1_is_file)) { 1475 assert(Z_OP_TYPE(opline->op1) == IS_CONST); 1476 if (!shallow_copy) { 1477 efree(Z_STRVAL(Z_OP_CONSTANT(opline->op1))); 1478 } 1479 if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) { 1480 assert(entry_php->filepath); 1481 ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op1), entry_php->filepath, entry_php->filepath_len, !shallow_copy); 1482 TRACE("restored op1 constant: %s", entry_php->filepath); 1483 } 1484 #ifdef IS_UNICODE 1485 else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) { 1486 assert(entry_php->ufilepath); 1487 ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op1), entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy); 1488 } 1489 #endif 1490 else { 1491 assert(0); 1492 } 1493 } 1494 else if ((oplineinfo & xcache_op1_is_dir)) { 1495 assert(Z_OP_TYPE(opline->op1) == IS_CONST); 1496 if (!shallow_copy) { 1497 efree(Z_STRVAL(Z_OP_CONSTANT(opline->op1))); 1498 } 1499 if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_STRING) { 1500 assert(entry_php->dirpath); 1501 TRACE("restored op1 constant: %s", entry_php->dirpath); 1502 ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op1), entry_php->dirpath, entry_php->dirpath_len, !shallow_copy); 1503 } 1504 #ifdef IS_UNICODE 1505 else if (Z_TYPE(Z_OP_CONSTANT(opline->op1)) == IS_UNICODE) { 1506 assert(!entry_php->udirpath); 1507 ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op1), entry_php->udirpath, entry_php->udirpath_len, !shallow_copy); 1508 } 1509 #endif 1510 else { 1511 assert(0); 1512 } 1513 } 1514 1515 if ((oplineinfo & xcache_op2_is_file)) { 1516 assert(Z_OP_TYPE(opline->op2) == IS_CONST); 1517 if (!shallow_copy) { 1518 efree(Z_STRVAL(Z_OP_CONSTANT(opline->op2))); 1519 } 1520 if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) { 1521 assert(entry_php->filepath); 1522 TRACE("restored op2 constant: %s", entry_php->filepath); 1523 ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op2), entry_php->filepath, entry_php->filepath_len, !shallow_copy); 1524 } 1525 #ifdef IS_UNICODE 1526 else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) { 1527 assert(entry_php->ufilepath); 1528 ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op2), entry_php->ufilepath, entry_php->ufilepath_len, !shallow_copy); 1529 } 1530 #endif 1531 else { 1532 assert(0); 1533 } 1534 } 1535 else if ((oplineinfo & xcache_op2_is_dir)) { 1536 assert(Z_OP_TYPE(opline->op2) == IS_CONST); 1537 if (!shallow_copy) { 1538 efree(Z_STRVAL(Z_OP_CONSTANT(opline->op2))); 1539 } 1540 if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_STRING) { 1541 assert(entry_php->dirpath); 1542 TRACE("restored op2 constant: %s", entry_php->dirpath); 1543 ZVAL_STRINGL(&Z_OP_CONSTANT(opline->op2), entry_php->dirpath, entry_php->dirpath_len, !shallow_copy); 1544 } 1545 #ifdef IS_UNICODE 1546 else if (Z_TYPE(Z_OP_CONSTANT(opline->op2)) == IS_UNICODE) { 1547 assert(entry_php->udirpath); 1548 ZVAL_UNICODEL(&Z_OP_CONSTANT(opline->op2), entry_php->udirpath, entry_php->udirpath_len, !shallow_copy); 1549 } 1550 #endif 1551 else { 1552 assert(0); 1553 } 1554 } 1555 } 1556 #endif /* ZEND_ENGINE_2_4 */ 1557 } 1558 /* }}} */ 1559 static void xc_free_op_array_info(xc_op_array_info_t *op_array_info TSRMLS_DC) /* {{{ */ 1560 { 1561 #ifdef ZEND_ENGINE_2_4 1562 if (op_array_info->literalinfos) { 1563 efree(op_array_info->literalinfos); 1564 } 1565 #else 1566 if (op_array_info->oplineinfos) { 1567 efree(op_array_info->oplineinfos); 1568 } 1569 #endif 1570 } 1571 /* }}} */ 1572 static void xc_free_php(xc_entry_data_php_t *php TSRMLS_DC) /* {{{ */ 1573 { 1574 zend_uint i; 1575 if (php->classinfos) { 1576 for (i = 0; i < php->classinfo_cnt; i ++) { 1577 xc_classinfo_t *classinfo = &php->classinfos[i]; 1578 zend_uint j; 1579 1580 for (j = 0; j < classinfo->methodinfo_cnt; j ++) { 1581 xc_free_op_array_info(&classinfo->methodinfos[j] TSRMLS_CC); 1582 } 1583 1584 if (classinfo->methodinfos) { 1585 efree(classinfo->methodinfos); 1586 } 1587 } 1588 } 1589 if (php->funcinfos) { 1590 for (i = 0; i < php->funcinfo_cnt; i ++) { 1591 xc_free_op_array_info(&php->funcinfos[i].op_array_info TSRMLS_CC); 1592 } 1593 } 1594 xc_free_op_array_info(&php->op_array_info TSRMLS_CC); 1595 1596 #define X_FREE(var) do {\ 1597 if (php->var) { \ 1598 efree(php->var); \ 1599 } \ 1600 } while (0) 1601 1602 #ifdef ZEND_ENGINE_2_1 1603 X_FREE(autoglobals); 1604 #endif 1605 X_FREE(classinfos); 1606 X_FREE(funcinfos); 1607 #ifdef HAVE_XCACHE_CONSTANT 1608 X_FREE(constinfos); 1609 #endif 1610 #undef X_FREE 1611 } 1612 /* }}} */ 1613 static void xc_compile_php(xc_compiler_t *compiler, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */ 1614 { 1615 zend_uint old_constinfo_cnt, old_funcinfo_cnt, old_classinfo_cnt; 1616 zend_bool catched = 0; 1617 1618 /* {{{ compile */ 1619 TRACE("compiling %s", h->opened_path ? h->opened_path : h->filename); 1620 1621 old_classinfo_cnt = zend_hash_num_elements(CG(class_table)); 1622 old_funcinfo_cnt = zend_hash_num_elements(CG(function_table)); 1623 old_constinfo_cnt = zend_hash_num_elements(EG(zend_constants)); 1624 1625 zend_try { 1626 compiler->new_php.op_array = old_compile_file(h, type TSRMLS_CC); 1627 } zend_catch { 1628 catched = 1; 1629 } zend_end_try(); 1630 1631 if (catched) { 1632 goto err_bailout; 1633 } 1634 1635 if (compiler->new_php.op_array == NULL) { 1636 goto err_op_array; 1637 } 1638 1639 if (!XG(initial_compile_file_called)) { 1640 TRACE("%s", "!initial_compile_file_called, give up"); 1641 return; 1642 } 1643 1644 /* }}} */ 1645 /* {{{ prepare */ 1646 zend_restore_compiled_filename(h->opened_path ? h->opened_path : (char *) h->filename TSRMLS_CC); 1647 1648 #ifdef HAVE_XCACHE_CONSTANT 1649 compiler->new_php.constinfo_cnt = zend_hash_num_elements(EG(zend_constants)) - old_constinfo_cnt; 1650 #endif 1651 compiler->new_php.funcinfo_cnt = zend_hash_num_elements(CG(function_table)) - old_funcinfo_cnt; 1652 compiler->new_php.classinfo_cnt = zend_hash_num_elements(CG(class_table)) - old_classinfo_cnt; 1653 #ifdef ZEND_ENGINE_2_1 1654 /* {{{ count new_php.autoglobal_cnt */ { 1655 Bucket *b; 1656 1657 compiler->new_php.autoglobal_cnt = 0; 1658 for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) { 1659 zend_auto_global *auto_global = (zend_auto_global *) b->pData; 1660 /* check if actived */ 1661 if (auto_global->auto_global_callback && !auto_global->armed) { 1662 compiler->new_php.autoglobal_cnt ++; 1663 } 1664 } 1665 } 1666 /* }}} */ 1667 #endif 1668 1669 #define X_ALLOC_N(var, cnt) do { \ 1670 if (compiler->new_php.cnt) { \ 1671 ECALLOC_N(compiler->new_php.var, compiler->new_php.cnt); \ 1672 if (!compiler->new_php.var) { \ 1673 goto err_alloc; \ 1674 } \ 1675 } \ 1676 else { \ 1677 compiler->new_php.var = NULL; \ 1678 } \ 1679 } while (0) 1680 1681 #ifdef HAVE_XCACHE_CONSTANT 1682 X_ALLOC_N(constinfos, constinfo_cnt); 1683 #endif 1684 X_ALLOC_N(funcinfos, funcinfo_cnt); 1685 X_ALLOC_N(classinfos, classinfo_cnt); 1686 #ifdef ZEND_ENGINE_2_1 1687 X_ALLOC_N(autoglobals, autoglobal_cnt); 1688 #endif 1689 #undef X_ALLOC 1690 /* }}} */ 1691 1692 /* {{{ shallow copy, pointers only */ { 1693 Bucket *b; 1694 zend_uint i; 1695 zend_uint j; 1696 1697 #define COPY_H(vartype, var, cnt, name, datatype) do { \ 1698 for (i = 0, j = 0; b; i ++, b = b->pListNext) { \ 1699 vartype *data = &compiler->new_php.var[j]; \ 1700 \ 1701 if (i < old_##cnt) { \ 1702 continue; \ 1703 } \ 1704 j ++; \ 1705 \ 1706 assert(i < old_##cnt + compiler->new_php.cnt); \ 1707 assert(b->pData); \ 1708 memcpy(&data->name, b->pData, sizeof(datatype)); \ 1709 UNISW(NOTHING, data->type = b->key.type;) \ 1710 if (UNISW(1, b->key.type == IS_STRING)) { \ 1711 ZSTR_S(data->key) = BUCKET_KEY_S(b); \ 1712 } \ 1713 else { \ 1714 ZSTR_U(data->key) = BUCKET_KEY_U(b); \ 1715 } \ 1716 data->key_size = b->nKeyLength; \ 1717 data->h = b->h; \ 1718 } \ 1719 } while(0) 1720 1721 #ifdef HAVE_XCACHE_CONSTANT 1722 b = EG(zend_constants)->pListHead; COPY_H(xc_constinfo_t, constinfos, constinfo_cnt, constant, zend_constant); 1723 #endif 1724 b = CG(function_table)->pListHead; COPY_H(xc_funcinfo_t, funcinfos, funcinfo_cnt, func, zend_function); 1725 b = CG(class_table)->pListHead; COPY_H(xc_classinfo_t, classinfos, classinfo_cnt, cest, xc_cest_t); 1726 1727 #undef COPY_H 1728 1729 /* for ZE1, cest need to be fixed inside store */ 1730 1731 #ifdef ZEND_ENGINE_2_1 1732 /* scan for acatived auto globals */ 1733 i = 0; 1734 for (b = CG(auto_globals)->pListHead; b != NULL; b = b->pListNext) { 1735 zend_auto_global *auto_global = (zend_auto_global *) b->pData; 1736 /* check if actived */ 1737 if (auto_global->auto_global_callback && !auto_global->armed) { 1738 xc_autoglobal_t *data = &compiler->new_php.autoglobals[i]; 1739 1740 assert(i < compiler->new_php.autoglobal_cnt); 1741 i ++; 1742 UNISW(NOTHING, data->type = b->key.type;) 1743 if (UNISW(1, b->key.type == IS_STRING)) { 1744 ZSTR_S(data->key) = BUCKET_KEY_S(b); 1745 } 1746 else { 1747 ZSTR_U(data->key) = BUCKET_KEY_U(b); 1748 } 1749 data->key_len = b->nKeyLength - 1; 1750 data->h = b->h; 1751 } 1752 } 1753 #endif 1754 } 1755 /* }}} */ 1756 1757 /* {{{ collect info for file/dir path */ { 1758 Bucket *b; 1759 xc_const_usage_t const_usage; 1760 unsigned int i; 1761 1762 xc_entry_php_init(&compiler->new_entry, zend_get_compiled_filename(TSRMLS_C) TSRMLS_CC); 1763 memset(&const_usage, 0, sizeof(const_usage)); 1764 1765 for (i = 0; i < compiler->new_php.classinfo_cnt; i ++) { 1766 xc_classinfo_t *classinfo = &compiler->new_php.classinfos[i]; 1767 zend_class_entry *ce = CestToCePtr(classinfo->cest); 1768 classinfo->methodinfo_cnt = ce->function_table.nTableSize; 1769 if (classinfo->methodinfo_cnt) { 1770 int j; 1771 1772 ECALLOC_N(classinfo->methodinfos, classinfo->methodinfo_cnt); 1773 if (!classinfo->methodinfos) { 1774 goto err_alloc; 1775 } 1776 1777 for (j = 0, b = ce->function_table.pListHead; b; j ++, b = b->pListNext) { 1778 xc_collect_op_array_info(compiler, &const_usage, &classinfo->methodinfos[j], (zend_op_array *) b->pData TSRMLS_CC); 1779 } 1780 } 1781 else { 1782 classinfo->methodinfos = NULL; 1783 } 1784 } 1785 1786 for (i = 0; i < compiler->new_php.funcinfo_cnt; i ++) { 1787 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); 1788 } 1789 1790 xc_collect_op_array_info(compiler, &const_usage, &compiler->new_php.op_array_info, compiler->new_php.op_array TSRMLS_CC); 1791 1792 /* file/dir path free unused */ 1793 #define X_FREE_UNUSED(var) \ 1794 if (!const_usage.var##path_used) { \ 1795 efree(compiler->new_entry.var##path); \ 1796 compiler->new_entry.var##path = NULL; \ 1797 compiler->new_entry.var##path_len = 0; \ 1798 } 1799 /* filepath is required to restore op_array->filename, so no free filepath here */ 1800 X_FREE_UNUSED(dir) 1801 #ifdef IS_UNICODE 1802 X_FREE_UNUSED(ufile) 1803 X_FREE_UNUSED(udir) 1804 #endif 1805 #undef X_FREE_UNUSED 1806 } 1807 /* }}} */ 1808 #ifdef XCACHE_ERROR_CACHING 1809 compiler->new_php.compilererrors = xc_sandbox_compilererrors(TSRMLS_C); 1810 compiler->new_php.compilererror_cnt = xc_sandbox_compilererror_cnt(TSRMLS_C); 1811 #endif 1812 #ifndef ZEND_COMPILE_DELAYED_BINDING 1813 /* {{{ find inherited classes that should be early-binding */ 1814 compiler->new_php.have_early_binding = 0; 1815 { 1816 zend_uint i; 1817 for (i = 0; i < compiler->new_php.classinfo_cnt; i ++) { 1818 compiler->new_php.classinfos[i].oplineno = -1; 1819 } 1820 } 1821 1822 xc_undo_pass_two(compiler->new_php.op_array TSRMLS_CC); 1823 xc_foreach_early_binding_class(compiler->new_php.op_array, xc_cache_early_binding_class_cb, (void *) &compiler->new_php TSRMLS_CC); 1824 xc_redo_pass_two(compiler->new_php.op_array TSRMLS_CC); 1825 /* }}} */ 1826 #endif 1827 1828 return; 1829 1830 err_alloc: 1831 xc_free_php(&compiler->new_php TSRMLS_CC); 1832 1833 err_bailout: 1834 err_op_array: 1835 1836 if (catched) { 1837 zend_bailout(); 1838 } 1839 } 1840 /* }}} */ 1841 static zend_op_array *xc_compile_restore(xc_entry_php_t *stored_entry, xc_entry_data_php_t *stored_php TSRMLS_DC) /* {{{ */ 1842 { 1843 zend_op_array *op_array; 1844 xc_entry_php_t restored_entry; 1845 xc_entry_data_php_t restored_php; 1846 zend_bool catched; 1847 zend_uint i; 1848 1849 /* still needed because in zend_language_scanner.l, require()/include() check file_handle.handle.stream.handle */ 1850 i = 1; 1851 zend_hash_add(&EG(included_files), stored_entry->entry.name.str.val, stored_entry->entry.name.str.len + 1, (void *)&i, sizeof(int), NULL); 1852 1853 CG(in_compilation) = 1; 1854 CG(compiled_filename) = stored_entry->entry.name.str.val; 1855 CG(zend_lineno) = 0; 1856 TRACE("restoring %d:%s", stored_entry->file_inode, stored_entry->entry.name.str.val); 1857 xc_processor_restore_xc_entry_php_t(&restored_entry, stored_entry TSRMLS_CC); 1858 xc_processor_restore_xc_entry_data_php_t(stored_entry, &restored_php, stored_php, xc_readonly_protection TSRMLS_CC); 1859 restored_entry.php = &restored_php; 1860 #ifdef SHOW_DPRINT 1861 xc_dprint(&restored_entry, 0 TSRMLS_CC); 1862 #endif 1863 1864 catched = 0; 1865 zend_try { 1866 op_array = xc_entry_install(&restored_entry TSRMLS_CC); 1867 } zend_catch { 1868 catched = 1; 1869 } zend_end_try(); 1870 1871 #ifdef HAVE_XCACHE_CONSTANT 1872 if (restored_php.constinfos) { 1873 efree(restored_php.constinfos); 1874 } 1875 #endif 1876 if (restored_php.funcinfos) { 1877 efree(restored_php.funcinfos); 1878 } 1879 if (restored_php.classinfos) { 1880 efree(restored_php.classinfos); 1881 } 1882 1883 if (catched) { 1884 zend_bailout(); 1885 } 1886 CG(in_compilation) = 0; 1887 CG(compiled_filename) = NULL; 1888 TRACE("restored %d:%s", stored_entry->file_inode, stored_entry->entry.name.str.val); 1889 return op_array; 1890 } 1891 /* }}} */ 47 /* }}} */ 48 1892 49 static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */ 1893 50 { 1894 51 XG(initial_compile_file_called) = 1; 1895 return origin_compile_file(h, type TSRMLS_CC); 1896 } 1897 /* }}} */ 1898 typedef struct xc_sandboxed_compiler_t { /* {{{ */ 1899 xc_compiler_t *compiler; 1900 /* input */ 1901 zend_file_handle *h; 1902 int type; 1903 1904 /* sandbox output */ 1905 xc_entry_php_t *stored_entry; 1906 xc_entry_data_php_t *stored_php; 1907 } xc_sandboxed_compiler_t; /* {{{ */ 1908 1909 static zend_op_array *xc_compile_file_sandboxed(void *data TSRMLS_DC) /* {{{ */ 1910 { 1911 xc_sandboxed_compiler_t *sandboxed_compiler = (xc_sandboxed_compiler_t *) data; 1912 xc_compiler_t *compiler = sandboxed_compiler->compiler; 1913 zend_bool catched = 0; 1914 xc_cache_t *cache = xc_php_caches[compiler->entry_hash.cacheid]; 1915 xc_entry_php_t *stored_entry; 1916 xc_entry_data_php_t *stored_php; 1917 1918 /* {{{ compile */ 1919 /* make compile inside sandbox */ 1920 #ifdef HAVE_XCACHE_CONSTANT 1921 compiler->new_php.constinfos = NULL; 1922 #endif 1923 compiler->new_php.funcinfos = NULL; 1924 compiler->new_php.classinfos = NULL; 1925 #ifdef ZEND_ENGINE_2_1 1926 compiler->new_php.autoglobals = NULL; 1927 #endif 1928 memset(&compiler->new_php.op_array_info, 0, sizeof(compiler->new_php.op_array_info)); 1929 1930 XG(initial_compile_file_called) = 0; 1931 zend_try { 1932 compiler->new_php.op_array = NULL; 1933 xc_compile_php(compiler, sandboxed_compiler->h, sandboxed_compiler->type TSRMLS_CC); 1934 } zend_catch { 1935 catched = 1; 1936 } zend_end_try(); 1937 1938 if (catched 1939 || !compiler->new_php.op_array /* possible ? */ 1940 || !XG(initial_compile_file_called)) { 1941 goto err_aftersandbox; 1942 } 1943 1944 /* }}} */ 1945 #ifdef SHOW_DPRINT 1946 compiler->new_entry.php = &compiler->new_php; 1947 xc_dprint(&compiler->new_entry, 0 TSRMLS_CC); 1948 #endif 1949 1950 stored_entry = NULL; 1951 stored_php = NULL; 1952 ENTER_LOCK_EX(cache) { /* {{{ php_store/entry_store */ 1953 /* php_store */ 1954 stored_php = xc_php_store_unlocked(cache, &compiler->new_php TSRMLS_CC); 1955 if (!stored_php) { 1956 /* error */ 1957 break; 1958 } 1959 /* entry_store */ 1960 compiler->new_entry.php = stored_php; 1961 stored_entry = xc_entry_php_store_unlocked(cache, compiler->entry_hash.entryslotid, &compiler->new_entry TSRMLS_CC); 1962 if (stored_entry) { 1963 xc_php_addref_unlocked(stored_php); 1964 TRACE(" cached %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val); 1965 xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC); 1966 } 1967 } LEAVE_LOCK_EX(cache); 1968 /* }}} */ 1969 TRACE("%s", stored_entry ? "stored" : "store failed"); 1970 1971 if (catched || !stored_php) { 1972 goto err_aftersandbox; 1973 } 1974 1975 cache->compiling = 0; 1976 xc_free_php(&compiler->new_php TSRMLS_CC); 1977 1978 if (stored_entry) { 1979 sandboxed_compiler->stored_entry = stored_entry; 1980 sandboxed_compiler->stored_php = stored_php; 1981 /* discard newly compiled result, restore from stored one */ 1982 if (compiler->new_php.op_array) { 1983 #ifdef ZEND_ENGINE_2 1984 destroy_op_array(compiler->new_php.op_array TSRMLS_CC); 1985 #else 1986 destroy_op_array(compiler->new_php.op_array); 1987 #endif 1988 efree(compiler->new_php.op_array); 1989 compiler->new_php.op_array = NULL; 1990 } 1991 return NULL; 1992 } 1993 else { 1994 return compiler->new_php.op_array; 1995 } 1996 1997 err_aftersandbox: 1998 xc_free_php(&compiler->new_php TSRMLS_CC); 1999 2000 cache->compiling = 0; 2001 if (catched) { 2002 cache->errors ++; 2003 zend_bailout(); 2004 } 2005 return compiler->new_php.op_array; 2006 } /* }}} */ 2007 static zend_op_array *xc_compile_file_cached(xc_compiler_t *compiler, zend_file_handle *h, int type TSRMLS_DC) /* {{{ */ 2008 { 2009 /* 2010 if (clog) { 2011 return old; 2012 } 2013 2014 if (cached_entry = getby entry_hash) { 2015 php = cached_entry.php; 2016 php = restore(php); 2017 return php; 2018 } 2019 else { 2020 if (!(php = getby md5)) { 2021 if (clog) { 2022 return old; 2023 } 2024 2025 inside_sandbox { 2026 php = compile; 2027 entry = create entries[entry]; 2028 } 2029 } 2030 2031 entry.php = php; 2032 return php; 2033 } 2034 */ 2035 2036 xc_entry_php_t *stored_entry; 2037 xc_entry_data_php_t *stored_php; 2038 zend_bool gaveup = 0; 2039 zend_bool catched = 0; 2040 zend_op_array *op_array; 2041 xc_cache_t *cache = xc_php_caches[compiler->entry_hash.cacheid]; 2042 xc_sandboxed_compiler_t sandboxed_compiler; 2043 2044 /* stale clogs precheck */ 2045 if (XG(request_time) - cache->compiling < 30) { 2046 cache->clogs ++; 2047 return old_compile_file(h, type TSRMLS_CC); 2048 } 2049 2050 /* {{{ entry_lookup/hit/md5_init/php_lookup */ 2051 stored_entry = NULL; 2052 stored_php = NULL; 2053 2054 ENTER_LOCK_EX(cache) { 2055 if (!compiler->opened_path && xc_entry_resolve_path_unlocked(compiler, compiler->filename, &stored_entry TSRMLS_CC) == SUCCESS) { 2056 compiler->opened_path = compiler->new_entry.entry.name.str.val; 2057 } 2058 else { 2059 if (!compiler->opened_path && xc_entry_php_resolve_opened_path(compiler, NULL TSRMLS_CC) != SUCCESS) { 2060 gaveup = 1; 2061 break; 2062 } 2063 2064 /* finalize name */ 2065 compiler->new_entry.entry.name.str.val = (char *) compiler->opened_path; 2066 compiler->new_entry.entry.name.str.len = strlen(compiler->new_entry.entry.name.str.val); 2067 2068 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); 2069 } 2070 2071 if (stored_entry) { 2072 xc_cache_hit_unlocked(cache TSRMLS_CC); 2073 2074 TRACE(" hit %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val); 2075 xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC); 2076 stored_php = stored_entry->php; 2077 break; 2078 } 2079 2080 TRACE("miss entry %d:%s", compiler->new_entry.file_inode, compiler->new_entry.entry.name.str.val); 2081 2082 if (xc_entry_data_php_init_md5(cache, compiler TSRMLS_CC) != SUCCESS) { 2083 gaveup = 1; 2084 break; 2085 } 2086 2087 stored_php = xc_php_find_unlocked(cache, &compiler->new_php TSRMLS_CC); 2088 2089 if (stored_php) { 2090 compiler->new_entry.php = stored_php; 2091 xc_entry_php_init(&compiler->new_entry, compiler->opened_path TSRMLS_CC); 2092 stored_entry = xc_entry_php_store_unlocked(cache, compiler->entry_hash.entryslotid, &compiler->new_entry TSRMLS_CC); 2093 if (stored_entry) { 2094 xc_php_addref_unlocked(stored_php); 2095 TRACE(" cached %d:%s, holding", compiler->new_entry.file_inode, stored_entry->entry.name.str.val); 2096 xc_entry_hold_php_unlocked(cache, stored_entry TSRMLS_CC); 2097 } 2098 else { 2099 gaveup = 1; 2100 } 2101 break; 2102 } 2103 2104 if (XG(request_time) - cache->compiling < 30) { 2105 TRACE("%s", "miss php, but compiling"); 2106 cache->clogs ++; 2107 gaveup = 1; 2108 break; 2109 } 2110 2111 TRACE("%s", "miss php, going to compile"); 2112 cache->compiling = XG(request_time); 2113 } LEAVE_LOCK_EX(cache); 2114 2115 if (catched) { 2116 cache->compiling = 0; 2117 zend_bailout(); 2118 } 2119 2120 /* found entry */ 2121 if (stored_entry && stored_php) { 2122 zend_llist_add_element(&CG(open_files), h); 2123 return xc_compile_restore(stored_entry, stored_php TSRMLS_CC); 2124 } 2125 2126 /* gaveup */ 2127 if (gaveup) { 2128 return old_compile_file(h, type TSRMLS_CC); 2129 } 2130 /* }}} */ 2131 2132 sandboxed_compiler.compiler = compiler; 2133 sandboxed_compiler.h = h; 2134 sandboxed_compiler.type = type; 2135 sandboxed_compiler.stored_php = NULL; 2136 sandboxed_compiler.stored_entry = NULL; 2137 op_array = xc_sandbox(xc_compile_file_sandboxed, (void *) &sandboxed_compiler, h->opened_path ? h->opened_path : h->filename TSRMLS_CC); 2138 if (sandboxed_compiler.stored_entry) { 2139 return xc_compile_restore(sandboxed_compiler.stored_entry, sandboxed_compiler.stored_php TSRMLS_CC); 2140 } 2141 else { 2142 return op_array; 2143 } 2144 } 2145 /* }}} */ 2146 static zend_op_array *xc_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */ 2147 { 2148 xc_compiler_t compiler; 2149 zend_op_array *op_array; 2150 2151 assert(xc_initized); 2152 2153 TRACE("xc_compile_file: type=%d name=%s", h->type, h->filename ? h->filename : "NULL"); 2154 2155 if (!XG(cacher) 2156 || !h->filename 2157 || !SG(request_info).path_translated 2158 || strstr(h->filename, "://") != NULL 2159 #ifdef ZEND_ENGINE_2_3 2160 /* supported by php_resolve_path */ 2161 || (!XG(stat) && strstr(PG(include_path), "://") != NULL) 2162 #else 2163 || strstr(PG(include_path), "://") != NULL 2164 #endif 2165 || !xc_shm || xc_shm->disabled 2166 ) { 2167 TRACE("%s", "cacher not enabled"); 2168 return old_compile_file(h, type TSRMLS_CC); 2169 } 2170 2171 /* {{{ entry_init_key */ 2172 compiler.opened_path = h->opened_path; 2173 compiler.filename = compiler.opened_path ? compiler.opened_path : h->filename; 2174 compiler.filename_len = strlen(compiler.filename); 2175 if (xc_entry_php_init_key(&compiler TSRMLS_CC) != SUCCESS) { 2176 TRACE("failed to init key for %s", compiler.filename); 2177 return old_compile_file(h, type TSRMLS_CC); 2178 } 2179 /* }}} */ 2180 2181 op_array = xc_compile_file_cached(&compiler, h, type TSRMLS_CC); 2182 2183 xc_entry_free_key_php(&compiler.new_entry TSRMLS_CC); 2184 2185 return op_array; 2186 } 2187 /* }}} */ 2188 2189 /* gdb helper functions, but N/A for coredump */ 2190 int xc_is_rw(const void *p) /* {{{ */ 2191 { 2192 xc_shm_t *shm; 2193 size_t i; 2194 2195 if (xc_php_caches) { 2196 for (i = 0; i < xc_php_hcache.size; i ++) { 2197 shm = xc_php_caches[i]->shm; 2198 if (shm->handlers->is_readwrite(shm, p)) { 2199 return 1; 2200 } 2201 } 2202 } 2203 2204 if (xc_var_caches) { 2205 for (i = 0; i < xc_var_hcache.size; i ++) { 2206 shm = xc_var_caches[i]->shm; 2207 if (shm->handlers->is_readwrite(shm, p)) { 2208 return 1; 2209 } 2210 } 2211 } 2212 return 0; 2213 } 2214 /* }}} */ 2215 int xc_is_ro(const void *p) /* {{{ */ 2216 { 2217 xc_shm_t *shm; 2218 size_t i; 2219 2220 if (xc_php_caches) { 2221 for (i = 0; i < xc_php_hcache.size; i ++) { 2222 shm = xc_php_caches[i]->shm; 2223 if (shm->handlers->is_readonly(shm, p)) { 2224 return 1; 2225 } 2226 } 2227 } 2228 2229 if (xc_var_caches) { 2230 for (i = 0; i < xc_var_hcache.size; i ++) { 2231 shm = xc_var_caches[i]->shm; 2232 if (shm->handlers->is_readonly(shm, p)) { 2233 return 1; 2234 } 2235 } 2236 } 2237 return 0; 2238 } 2239 /* }}} */ 2240 int xc_is_shm(const void *p) /* {{{ */ 2241 { 2242 return xc_is_ro(p) || xc_is_rw(p); 2243 } 2244 /* }}} */ 2245 2246 void xc_gc_add_op_array(xc_gc_op_array_t *gc_op_array TSRMLS_DC) /* {{{ */ 2247 { 2248 zend_llist_add_element(&XG(gc_op_arrays), (void *) gc_op_array); 2249 } 2250 /* }}} */ 2251 static void xc_gc_op_array(void *pDest) /* {{{ */ 2252 { 2253 xc_gc_op_array_t *op_array = (xc_gc_op_array_t *) pDest; 2254 zend_uint i; 2255 #ifdef ZEND_ENGINE_2 2256 if (op_array->arg_info) { 2257 for (i = 0; i < op_array->num_args; i++) { 2258 efree((char *) ZSTR_V(op_array->arg_info[i].name)); 2259 if (ZSTR_V(op_array->arg_info[i].class_name)) { 2260 efree((char *) ZSTR_V(op_array->arg_info[i].class_name)); 2261 } 2262 } 2263 efree(op_array->arg_info); 2264 } 2265 #endif 2266 if (op_array->opcodes) { 2267 efree(op_array->opcodes); 2268 } 52 return old_compile_file(h, type TSRMLS_CC); 2269 53 } 2270 54 /* }}} */ … … 2306 90 2307 91 zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC); 2308 zend_register_long_constant(ZEND_STRS("XC_TYPE_PHP"), XC_TYPE_PHP, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);2309 zend_register_long_constant(ZEND_STRS("XC_TYPE_VAR"), XC_TYPE_VAR, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);2310 92 zend_register_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC); 2311 93 zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC); 2312 94 return 0; 2313 }2314 /* }}} */2315 static void xc_cache_destroy(xc_cache_t **caches, xc_hash_t *hcache) /* {{{ */2316 {2317 size_t i;2318 xc_cache_t *cache;2319 2320 if (!caches) {2321 return;2322 }2323 2324 for (i = 0; i < hcache->size; i ++) {2325 cache = caches[i];2326 if (cache) {2327 if (cache->lck) {2328 xc_lock_destroy(cache->lck);2329 }2330 /* do NOT free2331 if (cache->entries) {2332 cache->mem->handlers->free(cache->mem, cache->entries);2333 }2334 cache->mem->handlers->free(cache->mem, cache);2335 */2336 cache->shm->handlers->memdestroy(cache->mem);2337 }2338 }2339 free(caches);2340 }2341 /* }}} */2342 static 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) /* {{{ */2343 {2344 xc_cache_t **caches = NULL, *cache;2345 xc_mem_t *mem;2346 time_t now = time(NULL);2347 size_t i;2348 xc_memsize_t memsize;2349 2350 memsize = shmsize / hcache->size;2351 2352 /* Don't let it break out of mem after ALIGNed2353 * This is important for2354 * Simply loop until it fit our need2355 */2356 while (ALIGN(memsize) * hcache->size > shmsize && ALIGN(memsize) != memsize) {2357 if (memsize < ALIGN(1)) {2358 CHECK(NULL, "cache too small");2359 }2360 memsize --;2361 }2362 2363 CHECK(caches = calloc(hcache->size, sizeof(xc_cache_t *)), "caches OOM");2364 2365 for (i = 0; i < hcache->size; i ++) {2366 CHECK(mem = shm->handlers->meminit(shm, memsize), "Failed init memory allocator");2367 CHECK(cache = mem->handlers->calloc(mem, 1, sizeof(xc_cache_t)), "cache OOM");2368 CHECK(cache->entries = mem->handlers->calloc(mem, hentry->size, sizeof(xc_entry_t*)), "entries OOM");2369 if (hphp) {2370 CHECK(cache->phps= mem->handlers->calloc(mem, hphp->size, sizeof(xc_entry_data_php_t*)), "phps OOM");2371 }2372 CHECK(cache->lck = xc_lock_init(NULL), "can't create lock");2373 2374 cache->hcache = hcache;2375 cache->hentry = hentry;2376 cache->hphp = hphp;2377 cache->shm = shm;2378 cache->mem = mem;2379 cache->cacheid = i;2380 cache->last_gc_deletes = now;2381 cache->last_gc_expires = now;2382 caches[i] = cache;2383 }2384 return caches;2385 2386 err:2387 if (caches) {2388 xc_cache_destroy(caches, hcache);2389 }2390 return NULL;2391 }2392 /* }}} */2393 static void xc_destroy() /* {{{ */2394 {2395 if (old_compile_file) {2396 zend_compile_file = old_compile_file;2397 old_compile_file = NULL;2398 }2399 2400 if (origin_compile_file) {2401 zend_compile_file = origin_compile_file;2402 origin_compile_file = NULL;2403 }2404 2405 if (xc_php_caches) {2406 xc_cache_destroy(xc_php_caches, &xc_php_hcache);2407 xc_php_caches = NULL;2408 }2409 2410 if (xc_var_caches) {2411 xc_cache_destroy(xc_var_caches, &xc_var_hcache);2412 xc_var_caches = NULL;2413 }2414 2415 if (xc_shm) {2416 xc_shm_destroy(xc_shm);2417 xc_shm = NULL;2418 }2419 2420 xc_initized = 0;2421 }2422 /* }}} */2423 static int xc_init(int module_number TSRMLS_DC) /* {{{ */2424 {2425 xc_shmsize_t shmsize = ALIGN(xc_php_size) + ALIGN(xc_var_size);2426 2427 xc_php_caches = xc_var_caches = NULL;2428 xc_shm = NULL;2429 2430 if (shmsize < (size_t) xc_php_size || shmsize < (size_t) xc_var_size) {2431 zend_error(E_ERROR, "XCache: neither xcache.size nor xcache.var_size can be negative");2432 goto err;2433 }2434 2435 if (xc_php_size || xc_var_size) {2436 CHECK(xc_shm = xc_shm_init(xc_shm_scheme, shmsize, xc_readonly_protection, xc_mmap_path, NULL), "Cannot create shm");2437 if (!xc_shm->handlers->can_readonly(xc_shm)) {2438 xc_readonly_protection = 0;2439 }2440 2441 if (xc_php_size) {2442 CHECK(xc_php_caches = xc_cache_init(xc_shm, &xc_php_hcache, &xc_php_hentry, &xc_php_hentry, xc_php_size), "failed init opcode cache");2443 }2444 2445 if (xc_var_size) {2446 CHECK(xc_var_caches = xc_cache_init(xc_shm, &xc_var_hcache, &xc_var_hentry, NULL, xc_var_size), "failed init variable cache");2447 }2448 }2449 return SUCCESS;2450 2451 err:2452 if (xc_php_caches || xc_var_caches) {2453 xc_destroy();2454 /* shm destroied in xc_destroy() */2455 }2456 else if (xc_shm) {2457 xc_destroy();2458 xc_shm_destroy(xc_shm);2459 xc_shm = NULL;2460 }2461 return 0;2462 }2463 /* }}} */2464 static void xc_request_init(TSRMLS_D) /* {{{ */2465 {2466 size_t i;2467 2468 if (!XG(internal_table_copied)) {2469 zend_function tmp_func;2470 xc_cest_t tmp_cest;2471 2472 #ifdef HAVE_XCACHE_CONSTANT2473 zend_hash_destroy(&XG(internal_constant_table));2474 #endif2475 zend_hash_destroy(&XG(internal_function_table));2476 zend_hash_destroy(&XG(internal_class_table));2477 2478 #ifdef HAVE_XCACHE_CONSTANT2479 zend_hash_init_ex(&XG(internal_constant_table), 20, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);2480 #endif2481 zend_hash_init_ex(&XG(internal_function_table), 100, NULL, NULL, 1, 0);2482 zend_hash_init_ex(&XG(internal_class_table), 10, NULL, NULL, 1, 0);2483 2484 #ifdef HAVE_XCACHE_CONSTANT2485 xc_copy_internal_zend_constants(&XG(internal_constant_table), EG(zend_constants));2486 #endif2487 zend_hash_copy(&XG(internal_function_table), CG(function_table), NULL, &tmp_func, sizeof(tmp_func));2488 zend_hash_copy(&XG(internal_class_table), CG(class_table), NULL, &tmp_cest, sizeof(tmp_cest));2489 2490 XG(internal_table_copied) = 1;2491 }2492 if (xc_php_caches && !XG(php_holds)) {2493 XG(php_holds) = calloc(xc_php_hcache.size, sizeof(xc_stack_t));2494 for (i = 0; i < xc_php_hcache.size; i ++) {2495 xc_stack_init(&XG(php_holds[i]));2496 }2497 }2498 2499 if (xc_var_caches && !XG(var_holds)) {2500 XG(var_holds) = calloc(xc_var_hcache.size, sizeof(xc_stack_t));2501 for (i = 0; i < xc_var_hcache.size; i ++) {2502 xc_stack_init(&XG(var_holds[i]));2503 }2504 }2505 2506 #ifdef ZEND_ENGINE_22507 zend_llist_init(&XG(gc_op_arrays), sizeof(xc_gc_op_array_t), xc_gc_op_array, 0);2508 #endif2509 2510 #if PHP_API_VERSION <= 200412252511 XG(request_time) = time(NULL);2512 #else2513 XG(request_time) = sapi_get_request_time(TSRMLS_C);2514 #endif2515 }2516 /* }}} */2517 static void xc_request_shutdown(TSRMLS_D) /* {{{ */2518 {2519 if (xc_shm && !xc_shm->disabled) {2520 xc_entry_unholds(TSRMLS_C);2521 xc_gc_expires_php(TSRMLS_C);2522 xc_gc_expires_var(TSRMLS_C);2523 xc_gc_deletes(TSRMLS_C);2524 }2525 #ifdef ZEND_ENGINE_22526 zend_llist_destroy(&XG(gc_op_arrays));2527 #endif2528 95 } 2529 96 /* }}} */ … … 2556 123 2557 124 if (xcache_globals->php_holds != NULL) { 2558 for (i = 0; i < xc _php_hcache.size; i ++) {125 for (i = 0; i < xcache_globals->php_holds_size; i ++) { 2559 126 xc_stack_destroy(&xcache_globals->php_holds[i]); 2560 127 } 2561 128 free(xcache_globals->php_holds); 2562 129 xcache_globals->php_holds = NULL; 130 xcache_globals->php_holds_size = 0; 2563 131 } 2564 132 2565 133 if (xcache_globals->var_holds != NULL) { 2566 for (i = 0; i < xc _var_hcache.size; i ++) {134 for (i = 0; i < xcache_globals->var_holds_size; i ++) { 2567 135 xc_stack_destroy(&xcache_globals->var_holds[i]); 2568 136 } 2569 137 free(xcache_globals->var_holds); 2570 138 xcache_globals->var_holds = NULL; 139 xcache_globals->var_holds_size = 0; 2571 140 } 2572 141 … … 2581 150 /* }}} */ 2582 151 2583 /* user functions */2584 static int xcache_admin_auth_check(TSRMLS_D) /* {{{ */2585 {2586 zval **server = NULL;2587 zval **user = NULL;2588 zval **pass = NULL;2589 char *admin_user = NULL;2590 char *admin_pass = NULL;2591 HashTable *ht;2592 2593 /* auth disabled, nothing to do.. */2594 if (!XG(auth_enabled)) {2595 return 1;2596 }2597 2598 if (cfg_get_string("xcache.admin.user", &admin_user) == FAILURE || !admin_user[0]) {2599 admin_user = NULL;2600 }2601 if (cfg_get_string("xcache.admin.pass", &admin_pass) == FAILURE || !admin_pass[0]) {2602 admin_pass = NULL;2603 }2604 2605 if (admin_user == NULL || admin_pass == NULL) {2606 php_error_docref(XCACHE_WIKI_URL "/InstallAdministration" TSRMLS_CC, E_ERROR,2607 "xcache.admin.user and/or xcache.admin.pass settings is not configured."2608 " Make sure you've modified the correct php ini file for your php used in webserver.");2609 zend_bailout();2610 }2611 if (strlen(admin_pass) != 32) {2612 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));2613 zend_bailout();2614 }2615 2616 #ifdef ZEND_ENGINE_2_12617 zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);2618 #endif2619 if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != SUCCESS || Z_TYPE_PP(server) != IS_ARRAY) {2620 php_error_docref(NULL TSRMLS_CC, E_ERROR, "_SERVER is corrupted");2621 zend_bailout();2622 }2623 ht = HASH_OF((*server));2624 2625 if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {2626 user = NULL;2627 }2628 else if (Z_TYPE_PP(user) != IS_STRING) {2629 user = NULL;2630 }2631 2632 if (zend_hash_find(ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW"), (void **) &pass) == FAILURE) {2633 pass = NULL;2634 }2635 else if (Z_TYPE_PP(pass) != IS_STRING) {2636 pass = NULL;2637 }2638 2639 if (user != NULL && pass != NULL && strcmp(admin_user, Z_STRVAL_PP(user)) == 0) {2640 PHP_MD5_CTX context;2641 char md5str[33];2642 unsigned char digest[16];2643 2644 PHP_MD5Init(&context);2645 PHP_MD5Update(&context, (unsigned char *) Z_STRVAL_PP(pass), Z_STRLEN_PP(pass));2646 PHP_MD5Final(digest, &context);2647 2648 md5str[0] = '\0';2649 make_digest(md5str, digest);2650 if (strcmp(admin_pass, md5str) == 0) {2651 return 1;2652 }2653 }2654 2655 #define STR "HTTP/1.0 401 Unauthorized"2656 sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);2657 #undef STR2658 #define STR "WWW-authenticate: Basic Realm=\"XCache Administration\""2659 sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);2660 #undef STR2661 #define STR "Content-type: text/html; charset=UTF-8"2662 sapi_add_header_ex(STR, sizeof(STR) - 1, 1, 1 TSRMLS_CC);2663 #undef STR2664 ZEND_PUTS("<html>\n");2665 ZEND_PUTS("<head><title>XCache Authentication Failed</title></head>\n");2666 ZEND_PUTS("<body>\n");2667 ZEND_PUTS("<h1>XCache Authentication Failed</h1>\n");2668 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");2669 ZEND_PUTS("<ul>\n");2670 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");2671 ZEND_PUTS("<li>Make sure the md5 password is generated correctly. You may use <a href=\"mkpassword.php\">mkpassword.php</a></li>\n");2672 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");2673 ZEND_PUTS("</ul>\n");2674 ZEND_PUTS("Check <a href=\"" XCACHE_WIKI_URL "/InstallAdministration\">XCache wiki page</a> for more information.\n");2675 ZEND_PUTS("</body>\n");2676 ZEND_PUTS("</html>\n");2677 2678 zend_bailout();2679 return 0;2680 }2681 /* }}} */2682 static void xc_clear(long type, xc_cache_t *cache TSRMLS_DC) /* {{{ */2683 {2684 xc_entry_t *e, *next;2685 int entryslotid, c;2686 2687 ENTER_LOCK(cache) {2688 for (entryslotid = 0, c = cache->hentry->size; entryslotid < c; entryslotid ++) {2689 for (e = cache->entries[entryslotid]; e; e = next) {2690 next = e->next;2691 xc_entry_remove_unlocked(type, cache, entryslotid, e TSRMLS_CC);2692 }2693 cache->entries[entryslotid] = NULL;2694 }2695 } LEAVE_LOCK(cache);2696 } /* }}} */2697 /* {{{ xcache_admin_operate */2698 typedef enum { XC_OP_COUNT, XC_OP_INFO, XC_OP_LIST, XC_OP_CLEAR } xcache_op_type;2699 static void xcache_admin_operate(xcache_op_type optype, INTERNAL_FUNCTION_PARAMETERS)2700 {2701 long type;2702 int size;2703 xc_cache_t **caches, *cache;2704 long id = 0;2705 2706 xcache_admin_auth_check(TSRMLS_C);2707 2708 if (!xc_initized || !xc_shm || xc_shm->disabled) {2709 RETURN_NULL();2710 }2711 2712 switch (optype) {2713 case XC_OP_COUNT:2714 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type) == FAILURE) {2715 return;2716 }2717 break;2718 case XC_OP_CLEAR:2719 id = -1;2720 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &type, &id) == FAILURE) {2721 return;2722 }2723 break;2724 default:2725 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &type, &id) == FAILURE) {2726 return;2727 }2728 }2729 2730 switch (type) {2731 case XC_TYPE_PHP:2732 size = xc_php_hcache.size;2733 caches = xc_php_caches;2734 break;2735 2736 case XC_TYPE_VAR:2737 size = xc_var_hcache.size;2738 caches = xc_var_caches;2739 break;2740 2741 default:2742 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown type %ld", type);2743 RETURN_FALSE;2744 }2745 2746 switch (optype) {2747 case XC_OP_COUNT:2748 RETURN_LONG(caches ? size : 0)2749 break;2750 2751 case XC_OP_INFO:2752 case XC_OP_LIST:2753 if (!caches || id < 0 || id >= size) {2754 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");2755 RETURN_FALSE;2756 }2757 2758 array_init(return_value);2759 2760 cache = caches[id];2761 ENTER_LOCK(cache) {2762 if (optype == XC_OP_INFO) {2763 xc_fillinfo_unlocked(type, cache, return_value TSRMLS_CC);2764 }2765 else {2766 xc_filllist_unlocked(type, cache, return_value TSRMLS_CC);2767 }2768 } LEAVE_LOCK(cache);2769 break;2770 2771 case XC_OP_CLEAR:2772 if (!caches || id < -1 || id >= size) {2773 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache not exists");2774 RETURN_FALSE;2775 }2776 2777 if (id == -1) {2778 for (id = 0; id < size; ++id) {2779 xc_clear(type, caches[id] TSRMLS_CC);2780 }2781 }2782 else {2783 xc_clear(type, caches[id] TSRMLS_CC);2784 }2785 2786 xc_gc_deletes(TSRMLS_C);2787 break;2788 2789 default:2790 assert(0);2791 }2792 }2793 /* }}} */2794 /* {{{ proto int xcache_count(int type)2795 Return count of cache on specified cache type */2796 PHP_FUNCTION(xcache_count)2797 {2798 xcache_admin_operate(XC_OP_COUNT, INTERNAL_FUNCTION_PARAM_PASSTHRU);2799 }2800 /* }}} */2801 /* {{{ proto array xcache_info(int type, int id)2802 Get cache info by id on specified cache type */2803 PHP_FUNCTION(xcache_info)2804 {2805 xcache_admin_operate(XC_OP_INFO, INTERNAL_FUNCTION_PARAM_PASSTHRU);2806 }2807 /* }}} */2808 /* {{{ proto array xcache_list(int type, int id)2809 Get cache entries list by id on specified cache type */2810 PHP_FUNCTION(xcache_list)2811 {2812 xcache_admin_operate(XC_OP_LIST, INTERNAL_FUNCTION_PARAM_PASSTHRU);2813 }2814 /* }}} */2815 /* {{{ proto array xcache_clear_cache(int type, [ int id = -1 ])2816 Clear cache by id on specified cache type */2817 PHP_FUNCTION(xcache_clear_cache)2818 {2819 xcache_admin_operate(XC_OP_CLEAR, INTERNAL_FUNCTION_PARAM_PASSTHRU);2820 }2821 /* }}} */2822 2823 #define VAR_DISABLED_WARNING() do { \2824 php_error_docref(NULL TSRMLS_CC, E_WARNING, "XCache var cache was not initialized properly. Check php log for actual reason"); \2825 } while (0)2826 2827 static int xc_entry_var_init_key(xc_entry_var_t *entry_var, xc_entry_hash_t *entry_hash, zval *name TSRMLS_DC) /* {{{ */2828 {2829 xc_hash_value_t hv;2830 2831 switch (name->type) {2832 #ifdef IS_UNICODE2833 case IS_UNICODE:2834 case IS_STRING:2835 #endif2836 default:2837 #ifdef IS_UNICODE2838 convert_to_unicode(name);2839 #else2840 convert_to_string(name);2841 #endif2842 }2843 2844 #ifdef IS_UNICODE2845 entry_var->name_type = name->type;2846 #endif2847 entry_var->entry.name = name->value;2848 2849 hv = xc_entry_hash_var((xc_entry_t *) entry_var TSRMLS_CC);2850 2851 entry_hash->cacheid = (hv & xc_var_hcache.mask);2852 hv >>= xc_var_hcache.bits;2853 entry_hash->entryslotid = (hv & xc_var_hentry.mask);2854 return SUCCESS;2855 }2856 /* }}} */2857 /* {{{ proto mixed xcache_get(string name)2858 Get cached data by specified name */2859 PHP_FUNCTION(xcache_get)2860 {2861 xc_entry_hash_t entry_hash;2862 xc_cache_t *cache;2863 xc_entry_var_t entry_var, *stored_entry_var;2864 zval *name;2865 2866 if (!xc_var_caches || !xc_shm || xc_shm->disabled) {2867 VAR_DISABLED_WARNING();2868 RETURN_NULL();2869 }2870 2871 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {2872 return;2873 }2874 xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);2875 cache = xc_var_caches[entry_hash.cacheid];2876 2877 ENTER_LOCK(cache) {2878 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);2879 if (stored_entry_var) {2880 /* return */2881 xc_processor_restore_zval(return_value, stored_entry_var->value, stored_entry_var->have_references TSRMLS_CC);2882 xc_cache_hit_unlocked(cache TSRMLS_CC);2883 }2884 else {2885 RETVAL_NULL();2886 }2887 } LEAVE_LOCK(cache);2888 }2889 /* }}} */2890 /* {{{ proto bool xcache_set(string name, mixed value [, int ttl])2891 Store data to cache by specified name */2892 PHP_FUNCTION(xcache_set)2893 {2894 xc_entry_hash_t entry_hash;2895 xc_cache_t *cache;2896 xc_entry_var_t entry_var, *stored_entry_var;2897 zval *name;2898 zval *value;2899 2900 if (!xc_var_caches || !xc_shm || xc_shm->disabled) {2901 VAR_DISABLED_WARNING();2902 RETURN_NULL();2903 }2904 2905 entry_var.entry.ttl = XG(var_ttl);2906 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &name, &value, &entry_var.entry.ttl) == FAILURE) {2907 return;2908 }2909 2910 if (Z_TYPE_P(value) == IS_OBJECT) {2911 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Objects cannot be stored in the variable cache. Use serialize before xcache_set");2912 RETURN_NULL();2913 }2914 2915 /* max ttl */2916 if (xc_var_maxttl && (!entry_var.entry.ttl || entry_var.entry.ttl > xc_var_maxttl)) {2917 entry_var.entry.ttl = xc_var_maxttl;2918 }2919 2920 xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);2921 cache = xc_var_caches[entry_hash.cacheid];2922 2923 ENTER_LOCK(cache) {2924 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);2925 if (stored_entry_var) {2926 xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);2927 }2928 entry_var.value = value;2929 RETVAL_BOOL(xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC) != NULL ? 1 : 0);2930 } LEAVE_LOCK(cache);2931 }2932 /* }}} */2933 /* {{{ proto bool xcache_isset(string name)2934 Check if an entry exists in cache by specified name */2935 PHP_FUNCTION(xcache_isset)2936 {2937 xc_entry_hash_t entry_hash;2938 xc_cache_t *cache;2939 xc_entry_var_t entry_var, *stored_entry_var;2940 zval *name;2941 2942 if (!xc_var_caches || !xc_shm || xc_shm->disabled) {2943 VAR_DISABLED_WARNING();2944 RETURN_FALSE;2945 }2946 2947 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {2948 return;2949 }2950 xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);2951 cache = xc_var_caches[entry_hash.cacheid];2952 2953 ENTER_LOCK(cache) {2954 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);2955 if (stored_entry_var) {2956 xc_cache_hit_unlocked(cache TSRMLS_CC);2957 RETVAL_TRUE;2958 /* return */2959 }2960 else {2961 RETVAL_FALSE;2962 }2963 2964 } LEAVE_LOCK(cache);2965 }2966 /* }}} */2967 /* {{{ proto bool xcache_unset(string name)2968 Unset existing data in cache by specified name */2969 PHP_FUNCTION(xcache_unset)2970 {2971 xc_entry_hash_t entry_hash;2972 xc_cache_t *cache;2973 xc_entry_var_t entry_var, *stored_entry_var;2974 zval *name;2975 2976 if (!xc_var_caches || !xc_shm || xc_shm->disabled) {2977 VAR_DISABLED_WARNING();2978 RETURN_FALSE;2979 }2980 2981 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {2982 return;2983 }2984 xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);2985 cache = xc_var_caches[entry_hash.cacheid];2986 2987 ENTER_LOCK(cache) {2988 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);2989 if (stored_entry_var) {2990 xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);2991 RETVAL_TRUE;2992 }2993 else {2994 RETVAL_FALSE;2995 }2996 } LEAVE_LOCK(cache);2997 }2998 /* }}} */2999 /* {{{ proto bool xcache_unset_by_prefix(string prefix)3000 Unset existing data in cache by specified prefix */3001 PHP_FUNCTION(xcache_unset_by_prefix)3002 {3003 zval *prefix;3004 int i, iend;3005 3006 if (!xc_var_caches || !xc_shm || xc_shm->disabled) {3007 VAR_DISABLED_WARNING();3008 RETURN_FALSE;3009 }3010 3011 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &prefix) == FAILURE) {3012 return;3013 }3014 3015 for (i = 0, iend = xc_var_hcache.size; i < iend; i ++) {3016 xc_cache_t *cache = xc_var_caches[i];3017 ENTER_LOCK(cache) {3018 int entryslotid, jend;3019 for (entryslotid = 0, jend = cache->hentry->size; entryslotid < jend; entryslotid ++) {3020 xc_entry_t *entry, *next;3021 for (entry = cache->entries[entryslotid]; entry; entry = next) {3022 next = entry->next;3023 if (xc_entry_has_prefix_unlocked(XC_TYPE_VAR, entry, prefix)) {3024 xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entryslotid, entry TSRMLS_CC);3025 }3026 }3027 }3028 } LEAVE_LOCK(cache);3029 }3030 }3031 /* }}} */3032 static inline void xc_var_inc_dec(int inc, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */3033 {3034 xc_entry_hash_t entry_hash;3035 xc_cache_t *cache;3036 xc_entry_var_t entry_var, *stored_entry_var;3037 zval *name;3038 long count = 1;3039 long value = 0;3040 zval oldzval;3041 3042 if (!xc_var_caches || !xc_shm || xc_shm->disabled) {3043 VAR_DISABLED_WARNING();3044 RETURN_NULL();3045 }3046 3047 entry_var.entry.ttl = XG(var_ttl);3048 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &name, &count, &entry_var.entry.ttl) == FAILURE) {3049 return;3050 }3051 3052 /* max ttl */3053 if (xc_var_maxttl && (!entry_var.entry.ttl || entry_var.entry.ttl > xc_var_maxttl)) {3054 entry_var.entry.ttl = xc_var_maxttl;3055 }3056 3057 xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);3058 cache = xc_var_caches[entry_hash.cacheid];3059 3060 ENTER_LOCK(cache) {3061 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);3062 if (stored_entry_var) {3063 TRACE("incdec: got entry_var %s", entry_var.entry.name.str.val);3064 /* do it in place */3065 if (Z_TYPE_P(stored_entry_var->value) == IS_LONG) {3066 zval *zv;3067 stored_entry_var->entry.ctime = XG(request_time);3068 stored_entry_var->entry.ttl = entry_var.entry.ttl;3069 TRACE("%s", "incdec: islong");3070 value = Z_LVAL_P(stored_entry_var->value);3071 value += (inc == 1 ? count : - count);3072 RETVAL_LONG(value);3073 3074 zv = (zval *) cache->shm->handlers->to_readwrite(cache->shm, (char *) stored_entry_var->value);3075 Z_LVAL_P(zv) = value;3076 ++cache->updates;3077 break; /* leave lock */3078 }3079 3080 TRACE("%s", "incdec: notlong");3081 xc_processor_restore_zval(&oldzval, stored_entry_var->value, stored_entry_var->have_references TSRMLS_CC);3082 convert_to_long(&oldzval);3083 value = Z_LVAL(oldzval);3084 zval_dtor(&oldzval);3085 }3086 else {3087 TRACE("incdec: %s not found", entry_var.entry.name.str.val);3088 }3089 3090 value += (inc == 1 ? count : - count);3091 RETVAL_LONG(value);3092 entry_var.value = return_value;3093 3094 if (stored_entry_var) {3095 entry_var.entry.atime = stored_entry_var->entry.atime;3096 entry_var.entry.ctime = stored_entry_var->entry.ctime;3097 entry_var.entry.hits = stored_entry_var->entry.hits;3098 xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entry_hash.entryslotid, (xc_entry_t *) stored_entry_var TSRMLS_CC);3099 }3100 xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC);3101 } LEAVE_LOCK(cache);3102 }3103 /* }}} */3104 /* {{{ proto int xcache_inc(string name [, int value [, int ttl]])3105 Increase an int counter in cache by specified name, create it if not exists */3106 PHP_FUNCTION(xcache_inc)3107 {3108 xc_var_inc_dec(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);3109 }3110 /* }}} */3111 /* {{{ proto int xcache_dec(string name [, int value [, int ttl]])3112 Decrease an int counter in cache by specified name, create it if not exists */3113 PHP_FUNCTION(xcache_dec)3114 {3115 xc_var_inc_dec(-1, INTERNAL_FUNCTION_PARAM_PASSTHRU);3116 }3117 /* }}} */3118 152 /* {{{ proto int xcache_get_refcount(mixed variable) 3119 153 XCache internal uses only: Get reference count of variable */ … … 3337 371 static zend_function_entry xcache_functions[] = /* {{{ */ 3338 372 { 3339 PHP_FE(xcache_count, NULL)3340 PHP_FE(xcache_info, NULL)3341 PHP_FE(xcache_list, NULL)3342 PHP_FE(xcache_clear_cache, NULL)3343 373 PHP_FE(xcache_coredump, NULL) 3344 374 #ifdef HAVE_XCACHE_ASSEMBLER … … 3359 389 PHP_FE(xcache_get_opcode_spec, NULL) 3360 390 PHP_FE(xcache_is_autoglobal, NULL) 3361 PHP_FE(xcache_inc, NULL)3362 PHP_FE(xcache_dec, NULL)3363 PHP_FE(xcache_get, NULL)3364 PHP_FE(xcache_set, NULL)3365 PHP_FE(xcache_isset, NULL)3366 PHP_FE(xcache_unset, NULL)3367 PHP_FE(xcache_unset_by_prefix, NULL)3368 391 PHP_FE(xcache_get_refcount, NULL) 3369 392 PHP_FE(xcache_get_isref, arginfo_xcache_get_isref) … … 3514 537 if (xc_disable_on_crash) { 3515 538 xc_disable_on_crash = 0; 3516 if (xc_shm) { 3517 xc_shm->disabled = 1; 3518 } 539 xc_cacher_disable(); 3519 540 } 3520 541 raise(sig); … … 3523 544 #endif 3524 545 3525 static void xc_zend_startup_last() /* {{{ */3526 {3527 if (xc_php_size) {3528 old_compile_file = zend_compile_file;3529 zend_compile_file = xc_compile_file;3530 }3531 }3532 /* }}} */3533 546 static startup_func_t xc_last_ext_startup; 3534 547 static int xc_zend_startup_last_hook(zend_extension *extension) /* {{{ */ … … 3547 560 assert(xc_llist_zend_extension); 3548 561 xcache_llist_prepend(&zend_extensions, xc_llist_zend_extension); 3549 3550 xc_zend_startup_last();3551 562 return SUCCESS; 3552 563 } … … 3554 565 static int xc_zend_startup(zend_extension *extension) /* {{{ */ 3555 566 { 3556 o rigin_compile_file = zend_compile_file;567 old_compile_file = zend_compile_file; 3557 568 zend_compile_file = xc_check_initial_compile_file; 3558 569 … … 3575 586 ext->startup = xc_zend_startup_last_hook; 3576 587 } 3577 else {3578 xc_zend_startup_last();3579 }3580 588 return SUCCESS; 3581 589 } … … 3586 594 /* }}} */ 3587 595 /* {{{ zend extension definition structure */ 3588 static zend_extension zend_extension_entry = {596 static zend_extension xc_zend_extension_entry = { 3589 597 XCACHE_NAME, 3590 598 XCACHE_VERSION, … … 3608 616 3609 617 /* {{{ PHP_INI */ 3610 #ifdef ZEND_WIN323611 # define DEFAULT_PATH "xcache"3612 #else3613 # define DEFAULT_PATH "/dev/zero"3614 #endif3615 618 PHP_INI_BEGIN() 3616 PHP_INI_ENTRY1 ("xcache.mmap_path", DEFAULT_PATH, PHP_INI_SYSTEM, xcache_OnUpdateString, &xc_mmap_path)3617 619 PHP_INI_ENTRY1 ("xcache.coredump_directory", "", PHP_INI_SYSTEM, xcache_OnUpdateString, &xc_coredump_dir) 3618 620 PHP_INI_ENTRY1 ("xcache.disable_on_crash", "0", PHP_INI_SYSTEM, xcache_OnUpdateBool, &xc_disable_on_crash) 3619 621 PHP_INI_ENTRY1 ("xcache.test", "0", PHP_INI_SYSTEM, xcache_OnUpdateBool, &xc_test) 3620 PHP_INI_ENTRY1 ("xcache.readonly_protection", "0", PHP_INI_SYSTEM, xcache_OnUpdateBool, &xc_readonly_protection)3621 /* opcode cache */3622 PHP_INI_ENTRY1 ("xcache.size", "0", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)3623 PHP_INI_ENTRY1 ("xcache.count", "1", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)3624 PHP_INI_ENTRY1 ("xcache.slots", "8K", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)3625 PHP_INI_ENTRY1 ("xcache.shm_scheme", "mmap", PHP_INI_SYSTEM, xcache_OnUpdateString, &xc_shm_scheme)3626 PHP_INI_ENTRY1 ("xcache.ttl", "0", PHP_INI_SYSTEM, xcache_OnUpdateULong, &xc_php_ttl)3627 PHP_INI_ENTRY1 ("xcache.gc_interval", "0", PHP_INI_SYSTEM, xcache_OnUpdateULong, &xc_php_gc_interval)3628 /* var cache */3629 PHP_INI_ENTRY1 ("xcache.var_size", "0", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)3630 PHP_INI_ENTRY1 ("xcache.var_count", "1", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)3631 PHP_INI_ENTRY1 ("xcache.var_slots", "8K", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)3632 PHP_INI_ENTRY1 ("xcache.var_maxttl", "0", PHP_INI_SYSTEM, xcache_OnUpdateULong, &xc_var_maxttl)3633 PHP_INI_ENTRY1 ("xcache.var_gc_interval", "120", PHP_INI_SYSTEM, xcache_OnUpdateULong, &xc_var_gc_interval)3634 3635 STD_PHP_INI_BOOLEAN("xcache.cacher", "1", PHP_INI_ALL, OnUpdateBool, cacher, zend_xcache_globals, xcache_globals)3636 STD_PHP_INI_BOOLEAN("xcache.stat", "1", PHP_INI_ALL, OnUpdateBool, stat, zend_xcache_globals, xcache_globals)3637 STD_PHP_INI_BOOLEAN("xcache.admin.enable_auth", "1", PHP_INI_SYSTEM, OnUpdateBool, auth_enabled, zend_xcache_globals, xcache_globals)3638 622 STD_PHP_INI_BOOLEAN("xcache.experimental", "0", PHP_INI_ALL, OnUpdateBool, experimental, zend_xcache_globals, xcache_globals) 3639 STD_PHP_INI_ENTRY ("xcache.var_ttl", "0", PHP_INI_ALL, OnUpdateLong, var_ttl, zend_xcache_globals, xcache_globals)3640 623 PHP_INI_END() 3641 624 /* }}} */ 3642 625 static PHP_MINFO_FUNCTION(xcache) /* {{{ */ 3643 626 { 3644 char buf[100];3645 char *ptr;3646 int left, len;3647 xc_shm_scheme_t *scheme;3648 3649 627 php_info_print_table_start(); 3650 628 php_info_print_table_row(2, "XCache Version", XCACHE_VERSION); … … 3653 631 #endif 3654 632 php_info_print_table_row(2, "Modules Built", XCACHE_MODULES); 3655 php_info_print_table_row(2, "Readonly Protection", xc_readonly_protection ? "enabled" : "disabled");3656 #ifdef ZEND_ENGINE_2_13657 ptr = php_format_date("Y-m-d H:i:s", sizeof("Y-m-d H:i:s") - 1, xc_init_time, 1 TSRMLS_CC);3658 php_info_print_table_row(2, "Cache Init Time", ptr);3659 efree(ptr);3660 #else3661 snprintf(buf, sizeof(buf), "%lu", (long unsigned) xc_init_time);3662 php_info_print_table_row(2, "Cache Init Time", buf);3663 #endif3664 3665 #ifdef ZTS3666 snprintf(buf, sizeof(buf), "%lu.%lu", xc_init_instance_id, xc_init_instance_subid);3667 #else3668 snprintf(buf, sizeof(buf), "%lu", xc_init_instance_id);3669 #endif3670 php_info_print_table_row(2, "Cache Instance Id", buf);3671 3672 if (xc_php_size) {3673 ptr = _php_math_number_format(xc_php_size, 0, '.', ',');3674 snprintf(buf, sizeof(buf), "enabled, %s bytes, %lu split(s), with %lu slots each", ptr, xc_php_hcache.size, xc_php_hentry.size);3675 php_info_print_table_row(2, "Opcode Cache", buf);3676 efree(ptr);3677 }3678 else {3679 php_info_print_table_row(2, "Opcode Cache", "disabled");3680 }3681 if (xc_var_size) {3682 ptr = _php_math_number_format(xc_var_size, 0, '.', ',');3683 snprintf(buf, sizeof(buf), "enabled, %s bytes, %lu split(s), with %lu slots each", ptr, xc_var_hcache.size, xc_var_hentry.size);3684 php_info_print_table_row(2, "Variable Cache", buf);3685 efree(ptr);3686 }3687 else {3688 php_info_print_table_row(2, "Variable Cache", "disabled");3689 }3690 3691 left = sizeof(buf);3692 ptr = buf;3693 buf[0] = '\0';3694 for (scheme = xc_shm_scheme_first(); scheme; scheme = xc_shm_scheme_next(scheme)) {3695 len = snprintf(ptr, left, ptr == buf ? "%s" : ", %s", xc_shm_scheme_name(scheme));3696 left -= len;3697 ptr += len;3698 }3699 php_info_print_table_row(2, "Shared Memory Schemes", buf);3700 3701 633 php_info_print_table_end(); 3702 634 … … 3704 636 } 3705 637 /* }}} */ 3706 static int xc_config_hash(xc_hash_t *p, char *name, char *default_value) /* {{{ */3707 {3708 size_t bits, size;3709 char *value;3710 3711 if (cfg_get_string(name, &value) != SUCCESS) {3712 value = default_value;3713 }3714 3715 p->size = zend_atoi(value, strlen(value));3716 for (size = 1, bits = 1; size < p->size; bits ++, size <<= 1) {3717 /* empty body */3718 }3719 p->size = size;3720 p->bits = bits;3721 p->mask = size - 1;3722 3723 return SUCCESS;3724 }3725 /* }}} */3726 static int xc_config_long(zend_ulong *p, char *name, char *default_value) /* {{{ */3727 {3728 char *value;3729 3730 if (cfg_get_string(name, &value) != SUCCESS) {3731 value = default_value;3732 }3733 3734 *p = zend_atol(value, strlen(value));3735 return SUCCESS;3736 }3737 /* }}} */3738 638 static PHP_MINIT_FUNCTION(xcache) /* {{{ */ 3739 639 { 3740 char *env; 3741 zend_extension *ext; 3742 zend_llist_position lpos; 3743 3744 xcache_zend_extension_register(&zend_extension_entry, 1); 3745 ext = zend_get_extension("Zend Optimizer"); 3746 if (ext) { 3747 /* zend_optimizer.optimization_level>0 is not compatible with other cacher, disabling */ 3748 ext->op_array_handler = NULL; 3749 } 3750 /* cache if there's an op_array_ctor */ 3751 for (ext = zend_llist_get_first_ex(&zend_extensions, &lpos); 3752 ext; 3753 ext = zend_llist_get_next_ex(&zend_extensions, &lpos)) { 3754 if (ext->op_array_ctor) { 3755 xc_have_op_array_ctor = 1; 3756 break; 3757 } 3758 } 3759 640 /* must be the first */ 641 xcache_zend_extension_register(&xc_zend_extension_entry, 1); 3760 642 3761 643 #ifndef PHP_GINIT … … 3764 646 REGISTER_INI_ENTRIES(); 3765 647 3766 /* additional_functions requires PHP 5.3. TODO: find simpler way to do it */3767 #ifdef ZEND_ENGINE_2_33768 if (strcmp(sapi_module.name, "cgi-fcgi") == 0 && !sapi_module.additional_functions && !getenv("XCACHE_SKIP_FCGI_WARNING") && !getenv("GATEWAY_INTERFACE")) {3769 if ((getenv("PHP_FCGI_CHILDREN") == NULL) || (atoi(getenv("PHP_FCGI_CHILDREN")) < 1)) {3770 zend_error(E_WARNING, "PHP_FCGI_CHILDREN should be >= 1 and use 1 group of parent/childs model. Set XCACHE_SKIP_FCGI_WARNING=1 to skip this warning. See " XCACHE_WIKI_URL "/Faq");3771 }3772 }3773 #endif3774 3775 xc_config_long(&xc_php_size, "xcache.size", "0");3776 xc_config_hash(&xc_php_hcache, "xcache.count", "1");3777 xc_config_hash(&xc_php_hentry, "xcache.slots", "8K");3778 3779 xc_config_long(&xc_var_size, "xcache.var_size", "0");3780 xc_config_hash(&xc_var_hcache, "xcache.var_count", "1");3781 xc_config_hash(&xc_var_hentry, "xcache.var_slots", "8K");3782 3783 if (strcmp(sapi_module.name, "cli") == 0) {3784 if ((env = getenv("XCACHE_TEST")) != NULL) {3785 xc_test = atoi(env);3786 }3787 if (!xc_test) {3788 /* disable cache for cli except for testing */3789 xc_php_size = xc_var_size = 0;3790 }3791 }3792 3793 if (xc_php_size <= 0) {3794 xc_php_size = xc_php_hcache.size = 0;3795 }3796 if (xc_var_size <= 0) {3797 xc_var_size = xc_var_hcache.size = 0;3798 }3799 3800 648 if (xc_coredump_dir && xc_coredump_dir[0]) { 3801 649 xcache_init_crash_handler(); … … 3805 653 xc_shm_init_modules(); 3806 654 3807 if ((xc_php_size || xc_var_size) && xc_mmap_path && xc_mmap_path[0]) {3808 if (xc_init(module_number TSRMLS_CC) != SUCCESS) {3809 zend_error(E_ERROR, "XCache: Cannot init");3810 goto err_init;3811 }3812 xc_initized = 1;3813 xc_init_time = time(NULL);3814 #ifdef PHP_WIN323815 xc_init_instance_id = GetCurrentProcessId();3816 #else3817 xc_init_instance_id = getpid();3818 #endif3819 #ifdef ZTS3820 xc_init_instance_subid = tsrm_thread_id();3821 #endif3822 }3823 3824 655 #ifdef HAVE_XCACHE_OPTIMIZER 3825 656 xc_optimizer_startup_module(); 3826 657 #endif 658 #ifdef HAVE_XCACHE_CACHER 659 xc_cacher_startup_module(); 660 #endif 3827 661 #ifdef HAVE_XCACHE_COVERAGER 3828 662 xc_coverager_startup_module(); … … 3831 665 xc_disassembler_startup_module(); 3832 666 #endif 3833 xc_sandbox_module_init(module_number TSRMLS_CC);3834 667 return SUCCESS; 3835 668 … … 3838 671 } 3839 672 /* }}} */ 3840 /* {{{ PHP_MSHUTDOWN_FUNCTION(xcache) */ 3841 static PHP_MSHUTDOWN_FUNCTION(xcache) 3842 { 3843 xc_sandbox_module_shutdown(); 3844 3845 if (xc_initized) { 3846 xc_destroy(); 3847 } 3848 if (xc_mmap_path) { 3849 pefree(xc_mmap_path, 1); 3850 xc_mmap_path = NULL; 3851 } 3852 if (xc_shm_scheme) { 3853 pefree(xc_shm_scheme, 1); 3854 xc_shm_scheme = NULL; 673 static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */ 674 { 675 if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) { 676 zend_compile_file = old_compile_file; 677 old_compile_file = NULL; 3855 678 } 3856 679 … … 3870 693 #endif 3871 694 3872 xcache_zend_extension_unregister(&zend_extension_entry);3873 695 UNREGISTER_INI_ENTRIES(); 3874 return SUCCESS; 3875 } 3876 /* }}} */ 3877 /* {{{ PHP_RINIT_FUNCTION(xcache) */ 3878 static PHP_RINIT_FUNCTION(xcache) 3879 { 3880 xc_request_init(TSRMLS_C); 3881 return SUCCESS; 3882 } 3883 /* }}} */ 3884 /* {{{ PHP_RSHUTDOWN_FUNCTION(xcache) */ 3885 #ifndef ZEND_ENGINE_2 3886 static PHP_RSHUTDOWN_FUNCTION(xcache) 3887 #else 3888 static ZEND_MODULE_POST_ZEND_DEACTIVATE_D(xcache) 3889 #endif 3890 { 3891 #ifdef ZEND_ENGINE_2 3892 TSRMLS_FETCH(); 3893 #endif 3894 3895 xc_request_shutdown(TSRMLS_C); 696 xcache_zend_extension_unregister(&xc_zend_extension_entry); 3896 697 return SUCCESS; 3897 698 } … … 3921 722 PHP_MINIT(xcache), 3922 723 PHP_MSHUTDOWN(xcache), 3923 PHP_RINIT(xcache), 3924 #ifndef ZEND_ENGINE_2 3925 PHP_RSHUTDOWN(xcache), 3926 #else 3927 NULL, 3928 #endif 724 NULL, /* RINIT */ 725 NULL, /* RSHUTDOWN */ 3929 726 PHP_MINFO(xcache), 3930 727 XCACHE_VERSION, … … 3935 732 #endif 3936 733 #ifdef ZEND_ENGINE_2 3937 ZEND_MODULE_POST_ZEND_DEACTIVATE_N(xcache),734 NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */, 3938 735 #else 3939 736 NULL, -
trunk/xcache.h
r1035 r1040 260 260 void xc_fix_op_array_info(const xc_entry_php_t *xce, const xc_entry_data_php_t *php, zend_op_array *op_array, int shallow_copy, const xc_op_array_info_t *op_array_info TSRMLS_DC); 261 261 262 extern zend_bool xc_test; 263 262 264 #endif /* __XCACHE_H */ -
trunk/xcache/xc_shm.h
r982 r1040 6 6 struct _xc_shm_t { 7 7 const xc_shm_handlers_t *handlers; 8 zend_bool disabled;9 8 }; 10 9 #define XC_SHM_IMPL _xc_shm_t -
trunk/xcache_globals.h
r982 r1040 15 15 #endif 16 16 xc_stack_t *php_holds; 17 zend_uint php_holds_size; 17 18 xc_stack_t *var_holds; 19 zend_uint var_holds_size; 18 20 time_t request_time; 19 21 long var_ttl; 20 zend_bool auth_enabled;21 22 22 23 zend_llist gc_op_arrays;
Note: See TracChangeset
for help on using the changeset viewer.