root/ext/opcache/ZendAccelerator.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_accel_get_time
  2. is_stream_path
  3. is_cacheable_stream_path
  4. ZEND_FUNCTION
  5. accel_getcwd
  6. zend_accel_schedule_restart_if_necessary
  7. ZEND_INI_MH
  8. accel_restart_enter
  9. accel_restart_leave
  10. accel_restart_is_active
  11. accel_activate_add
  12. accel_deactivate_sub
  13. accel_unlock_all
  14. accel_new_interned_string_for_php
  15. accel_interned_strings_snapshot_for_php
  16. accel_interned_strings_restore_for_php
  17. accel_interned_strings_restore_state
  18. accel_interned_strings_save_state
  19. accel_find_interned_string
  20. accel_new_interned_string
  21. accel_use_shm_interned_strings
  22. kill_all_lockers
  23. accel_is_inactive
  24. zend_get_stream_timestamp
  25. zend_get_file_handle_timestamp_win
  26. zend_get_file_handle_timestamp
  27. do_validate_timestamps
  28. validate_timestamp_and_record
  29. accel_make_persistent_key
  30. zend_accel_invalidate
  31. zend_accel_add_key
  32. cache_script_in_file_cache
  33. cache_script_in_shared_memory
  34. zend_accel_get_auto_globals
  35. zend_accel_get_auto_globals_no_jit
  36. zend_accel_set_auto_globals
  37. zend_accel_init_auto_globals
  38. opcache_compile_file
  39. file_cache_compile_file
  40. persistent_compile_file
  41. persistent_stream_open_function
  42. persistent_zend_resolve_path
  43. zend_reset_cache_vars
  44. accel_reset_pcre_cache
  45. accel_activate
  46. accel_fast_zval_dtor
  47. accel_fast_hash_destroy
  48. zend_accel_fast_del_bucket
  49. zend_accel_fast_shutdown
  50. accel_post_deactivate
  51. accel_deactivate
  52. accelerator_remove_cb
  53. zps_startup_failure
  54. accel_find_sapi
  55. zend_accel_init_shm
  56. accel_globals_ctor
  57. accel_globals_internal_func_dtor
  58. accel_globals_dtor
  59. accel_gen_system_id
  60. accel_remap_huge_pages
  61. accel_move_code_to_huge_pages
  62. accel_move_code_to_huge_pages
  63. accel_startup
  64. accel_free_ts_resources
  65. accel_shutdown
  66. zend_accel_schedule_restart
  67. accelerator_shm_read_lock
  68. accelerator_shm_read_unlock

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend OPcache                                                         |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Andi Gutmans <andi@zend.com>                                |
  16    |          Zeev Suraski <zeev@zend.com>                                |
  17    |          Stanislav Malyshev <stas@zend.com>                          |
  18    |          Dmitry Stogov <dmitry@zend.com>                             |
  19    +----------------------------------------------------------------------+
  20 */
  21 
  22 #include "main/php.h"
  23 #include "main/php_globals.h"
  24 #include "zend.h"
  25 #include "zend_extensions.h"
  26 #include "zend_compile.h"
  27 #include "ZendAccelerator.h"
  28 #include "zend_persist.h"
  29 #include "zend_shared_alloc.h"
  30 #include "zend_accelerator_module.h"
  31 #include "zend_accelerator_blacklist.h"
  32 #include "zend_list.h"
  33 #include "zend_execute.h"
  34 #include "main/SAPI.h"
  35 #include "main/php_streams.h"
  36 #include "main/php_open_temporary_file.h"
  37 #include "zend_API.h"
  38 #include "zend_ini.h"
  39 #include "zend_virtual_cwd.h"
  40 #include "zend_accelerator_util_funcs.h"
  41 #include "zend_accelerator_hash.h"
  42 #include "ext/pcre/php_pcre.h"
  43 #include "ext/standard/md5.h"
  44 
  45 #ifdef HAVE_OPCACHE_FILE_CACHE
  46 # include "zend_file_cache.h"
  47 #endif
  48 
  49 #ifndef ZEND_WIN32
  50 #include  <netdb.h>
  51 #endif
  52 
  53 #ifdef ZEND_WIN32
  54 typedef int uid_t;
  55 typedef int gid_t;
  56 #include <io.h>
  57 #endif
  58 
  59 #ifndef ZEND_WIN32
  60 # include <sys/time.h>
  61 #else
  62 # include <process.h>
  63 #endif
  64 
  65 #ifdef HAVE_UNISTD_H
  66 # include <unistd.h>
  67 #endif
  68 #include <fcntl.h>
  69 #include <signal.h>
  70 #include <time.h>
  71 
  72 #ifndef ZEND_WIN32
  73 # include <sys/types.h>
  74 # include <sys/ipc.h>
  75 #endif
  76 
  77 #include <sys/stat.h>
  78 #include <errno.h>
  79 
  80 #define SHM_PROTECT() \
  81         do { \
  82                 if (ZCG(accel_directives).protect_memory) { \
  83                         zend_accel_shared_protect(1); \
  84                 } \
  85         } while (0)
  86 #define SHM_UNPROTECT() \
  87         do { \
  88                 if (ZCG(accel_directives).protect_memory) { \
  89                         zend_accel_shared_protect(0); \
  90                 } \
  91         } while (0)
  92 
  93 ZEND_EXTENSION();
  94 
  95 #ifndef ZTS
  96 zend_accel_globals accel_globals;
  97 #else
  98 int accel_globals_id;
  99 #if defined(COMPILE_DL_OPCACHE)
 100 ZEND_TSRMLS_CACHE_DEFINE()
 101 #endif
 102 #endif
 103 
 104 /* Points to the structure shared across all PHP processes */
 105 zend_accel_shared_globals *accel_shared_globals = NULL;
 106 
 107 /* true globals, no need for thread safety */
 108 zend_bool accel_startup_ok = 0;
 109 static char *zps_failure_reason = NULL;
 110 char *zps_api_failure_reason = NULL;
 111 #if ENABLE_FILE_CACHE_FALLBACK
 112 zend_bool fallback_process = 0; /* process uses file cache fallback */
 113 #endif
 114 
 115 static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type);
 116 static int (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle );
 117 static zend_string *(*accelerator_orig_zend_resolve_path)(const char *filename, int filename_len);
 118 static void (*orig_chdir)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
 119 static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
 120 
 121 #ifdef ZEND_WIN32
 122 # define INCREMENT(v) InterlockedIncrement64(&ZCSG(v))
 123 # define DECREMENT(v) InterlockedDecrement64(&ZCSG(v))
 124 # define LOCKVAL(v)   (ZCSG(v))
 125 #endif
 126 
 127 #ifdef ZEND_WIN32
 128 static time_t zend_accel_get_time(void)
 129 {
 130         FILETIME now;
 131         GetSystemTimeAsFileTime(&now);
 132 
 133         return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
 134 }
 135 #else
 136 # define zend_accel_get_time() time(NULL)
 137 #endif
 138 
 139 static inline int is_stream_path(const char *filename)
 140 {
 141         const char *p;
 142 
 143         for (p = filename;
 144              (*p >= 'a' && *p <= 'z') ||
 145              (*p >= 'A' && *p <= 'Z') ||
 146              (*p >= '0' && *p <= '9') ||
 147              *p == '+' || *p == '-' || *p == '.';
 148              p++);
 149         return ((p != filename) && (p[0] == ':') && (p[1] == '/') && (p[2] == '/'));
 150 }
 151 
 152 static inline int is_cacheable_stream_path(const char *filename)
 153 {
 154         return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
 155                memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
 156 }
 157 
 158 /* O+ overrides PHP chdir() function and remembers the current working directory
 159  * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
 160  * avoid getcwd() call.
 161  */
 162 static ZEND_FUNCTION(accel_chdir)
 163 {
 164         char cwd[MAXPATHLEN];
 165 
 166         orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
 167         if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
 168                 if (ZCG(cwd)) {
 169                         zend_string_release(ZCG(cwd));
 170                 }
 171                 ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
 172         } else {
 173                 if (ZCG(cwd)) {
 174                         zend_string_release(ZCG(cwd));
 175                         ZCG(cwd) = NULL;
 176                 }
 177         }
 178         ZCG(cwd_key_len) = 0;
 179         ZCG(cwd_check) = 1;
 180 }
 181 
 182 static inline zend_string* accel_getcwd(void)
 183 {
 184         if (ZCG(cwd)) {
 185                 return ZCG(cwd);
 186         } else {
 187                 char cwd[MAXPATHLEN + 1];
 188 
 189                 if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
 190                         return NULL;
 191                 }
 192                 ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
 193                 ZCG(cwd_key_len) = 0;
 194                 ZCG(cwd_check) = 1;
 195                 return ZCG(cwd);
 196         }
 197 }
 198 
 199 void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason)
 200 {
 201         if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
 202                 zend_accel_schedule_restart(reason);
 203         }
 204 }
 205 
 206 /* O+ tracks changes of "include_path" directive. It stores all the requested
 207  * values in ZCG(include_paths) shared hash table, current value in
 208  * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
 209  * ZCG(include_path_key).
 210  */
 211 static ZEND_INI_MH(accel_include_path_on_modify)
 212 {
 213         int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
 214 
 215         if (ret == SUCCESS) {
 216                 ZCG(include_path) = new_value;
 217                 ZCG(include_path_key_len) = 0;
 218                 ZCG(include_path_check) = 1;
 219         }
 220         return ret;
 221 }
 222 
 223 static inline void accel_restart_enter(void)
 224 {
 225 #ifdef ZEND_WIN32
 226         INCREMENT(restart_in);
 227 #else
 228         static const FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1);
 229 
 230         if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
 231                 zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1):  %s (%d)", strerror(errno), errno);
 232         }
 233 #endif
 234         ZCSG(restart_in_progress) = 1;
 235 }
 236 
 237 static inline void accel_restart_leave(void)
 238 {
 239 #ifdef ZEND_WIN32
 240         ZCSG(restart_in_progress) = 0;
 241         DECREMENT(restart_in);
 242 #else
 243         static const FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1);
 244 
 245         ZCSG(restart_in_progress) = 0;
 246         if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
 247                 zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1):  %s (%d)", strerror(errno), errno);
 248         }
 249 #endif
 250 }
 251 
 252 static inline int accel_restart_is_active(void)
 253 {
 254         if (ZCSG(restart_in_progress)) {
 255 #ifndef ZEND_WIN32
 256                 FLOCK_STRUCTURE(restart_check, F_WRLCK, SEEK_SET, 2, 1);
 257 
 258                 if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
 259                         zend_accel_error(ACCEL_LOG_DEBUG, "RestartC:  %s (%d)", strerror(errno), errno);
 260                         return FAILURE;
 261                 }
 262                 if (restart_check.l_type == F_UNLCK) {
 263                         ZCSG(restart_in_progress) = 0;
 264                         return 0;
 265                 } else {
 266                         return 1;
 267                 }
 268 #else
 269                 return LOCKVAL(restart_in) != 0;
 270 #endif
 271         }
 272         return 0;
 273 }
 274 
 275 /* Creates a read lock for SHM access */
 276 static inline int accel_activate_add(void)
 277 {
 278 #ifdef ZEND_WIN32
 279         INCREMENT(mem_usage);
 280 #else
 281         static const FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1);
 282 
 283         if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
 284                 zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1):  %s (%d)", strerror(errno), errno);
 285                 return FAILURE;
 286         }
 287 #endif
 288         return SUCCESS;
 289 }
 290 
 291 /* Releases a lock for SHM access */
 292 static inline void accel_deactivate_sub(void)
 293 {
 294 #ifdef ZEND_WIN32
 295         if (ZCG(counted)) {
 296                 DECREMENT(mem_usage);
 297                 ZCG(counted) = 0;
 298         }
 299 #else
 300         static const FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1);
 301 
 302         if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
 303                 zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1):  %s (%d)", strerror(errno), errno);
 304         }
 305 #endif
 306 }
 307 
 308 static inline void accel_unlock_all(void)
 309 {
 310 #ifdef ZEND_WIN32
 311         accel_deactivate_sub();
 312 #else
 313         static const FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0);
 314 
 315         if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
 316                 zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll:  %s (%d)", strerror(errno), errno);
 317         }
 318 #endif
 319 }
 320 
 321 /* Interned strings support */
 322 static zend_string *(*orig_new_interned_string)(zend_string *str);
 323 static void (*orig_interned_strings_snapshot)(void);
 324 static void (*orig_interned_strings_restore)(void);
 325 
 326 /* O+ disables creation of interned strings by regular PHP compiler, instead,
 327  * it creates interned strings in shared memory when saves a script.
 328  * Such interned strings are shared across all PHP processes
 329  */
 330 static zend_string *accel_new_interned_string_for_php(zend_string *str)
 331 {
 332         return str;
 333 }
 334 
 335 static void accel_interned_strings_snapshot_for_php(void)
 336 {
 337 }
 338 
 339 static void accel_interned_strings_restore_for_php(void)
 340 {
 341 }
 342 
 343 #ifndef ZTS
 344 static void accel_interned_strings_restore_state(void)
 345 {
 346     uint idx = ZCSG(interned_strings).nNumUsed;
 347     uint nIndex;
 348     Bucket *p;
 349 
 350         memset(ZCSG(interned_strings_saved_top),
 351                         0, ZCSG(interned_strings_top) - ZCSG(interned_strings_saved_top));
 352         ZCSG(interned_strings_top) = ZCSG(interned_strings_saved_top);
 353     while (idx > 0) {
 354         idx--;
 355                 p = ZCSG(interned_strings).arData + idx;
 356                 if ((char*)p->key < ZCSG(interned_strings_top)) break;
 357                 ZCSG(interned_strings).nNumUsed--;
 358                 ZCSG(interned_strings).nNumOfElements--;
 359 
 360                 nIndex = p->h | ZCSG(interned_strings).nTableMask;
 361                 if (HT_HASH(&ZCSG(interned_strings), nIndex) == HT_IDX_TO_HASH(idx)) {
 362                         HT_HASH(&ZCSG(interned_strings), nIndex) = Z_NEXT(p->val);
 363                 } else {
 364                         uint32_t prev = HT_HASH(&ZCSG(interned_strings), nIndex);
 365                         while (Z_NEXT(HT_HASH_TO_BUCKET(&ZCSG(interned_strings), prev)->val) != idx) {
 366                                 prev = Z_NEXT(HT_HASH_TO_BUCKET(&ZCSG(interned_strings), prev)->val);
 367                         }
 368                         Z_NEXT(HT_HASH_TO_BUCKET(&ZCSG(interned_strings), prev)->val) = Z_NEXT(p->val);
 369                 }
 370         }
 371 }
 372 
 373 static void accel_interned_strings_save_state(void)
 374 {
 375         ZCSG(interned_strings_saved_top) = ZCSG(interned_strings_top);
 376 }
 377 #endif
 378 
 379 #ifndef ZTS
 380 static zend_string *accel_find_interned_string(zend_string *str)
 381 {
 382 /* for now interned strings are supported only for non-ZTS build */
 383         zend_ulong h;
 384         uint nIndex;
 385         uint idx;
 386         Bucket *arData, *p;
 387 
 388         if (IS_ACCEL_INTERNED(str)) {
 389                 /* this is already an interned string */
 390                 return str;
 391         }
 392         if (!ZCG(counted)) {
 393                 if (accel_activate_add() == FAILURE) {
 394                         return str;
 395                 }
 396                 ZCG(counted) = 1;
 397         }
 398 
 399         h = zend_string_hash_val(str);
 400         nIndex = h | ZCSG(interned_strings).nTableMask;
 401 
 402         /* check for existing interned string */
 403         idx = HT_HASH(&ZCSG(interned_strings), nIndex);
 404         arData = ZCSG(interned_strings).arData;
 405         while (idx != HT_INVALID_IDX) {
 406                 p = HT_HASH_TO_BUCKET_EX(arData, idx);
 407                 if ((p->h == h) && (ZSTR_LEN(p->key) == ZSTR_LEN(str))) {
 408                         if (!memcmp(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str))) {
 409                                 return p->key;
 410                         }
 411                 }
 412                 idx = Z_NEXT(p->val);
 413         }
 414 
 415         return NULL;
 416 }
 417 #endif
 418 
 419 zend_string *accel_new_interned_string(zend_string *str)
 420 {
 421 /* for now interned strings are supported only for non-ZTS build */
 422 #ifndef ZTS
 423         zend_ulong h;
 424         uint nIndex;
 425         uint idx;
 426         Bucket *p;
 427 
 428 #ifdef HAVE_OPCACHE_FILE_CACHE
 429         if (ZCG(accel_directives).file_cache_only) {
 430                 return str;
 431         }
 432 #endif
 433 
 434         if (IS_ACCEL_INTERNED(str)) {
 435                 /* this is already an interned string */
 436                 return str;
 437         }
 438 
 439         h = zend_string_hash_val(str);
 440         nIndex = h | ZCSG(interned_strings).nTableMask;
 441 
 442         /* check for existing interned string */
 443         idx = HT_HASH(&ZCSG(interned_strings), nIndex);
 444         while (idx != HT_INVALID_IDX) {
 445                 p = HT_HASH_TO_BUCKET(&ZCSG(interned_strings), idx);
 446                 if ((p->h == h) && (ZSTR_LEN(p->key) == ZSTR_LEN(str))) {
 447                         if (!memcmp(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str))) {
 448                                 zend_string_release(str);
 449                                 return p->key;
 450                         }
 451                 }
 452                 idx = Z_NEXT(p->val);
 453         }
 454 
 455         if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str))) >=
 456             ZCSG(interned_strings_end)) {
 457             /* no memory, return the same non-interned string */
 458                 zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
 459                 return str;
 460         }
 461 
 462         /* create new interning string in shared interned strings buffer */
 463 
 464         idx = ZCSG(interned_strings).nNumUsed++;
 465         ZCSG(interned_strings).nNumOfElements++;
 466         p = ZCSG(interned_strings).arData + idx;
 467         p->key = (zend_string*) ZCSG(interned_strings_top);
 468         ZCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str)));
 469         p->h = h;
 470         GC_REFCOUNT(p->key) = 1;
 471 #if 1
 472         /* optimized single assignment */
 473         GC_TYPE_INFO(p->key) = IS_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << 8);
 474 #else
 475         GC_TYPE(p->key) = IS_STRING;
 476         GC_FLAGS(p->key) = IS_STR_INTERNED | IS_STR_PERMANENT;
 477 #endif
 478         ZSTR_H(p->key) = ZSTR_H(str);
 479         ZSTR_LEN(p->key) = ZSTR_LEN(str);
 480         memcpy(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str));
 481         ZVAL_INTERNED_STR(&p->val, p->key);
 482         Z_NEXT(p->val) = HT_HASH(&ZCSG(interned_strings), nIndex);
 483         HT_HASH(&ZCSG(interned_strings), nIndex) = HT_IDX_TO_HASH(idx);
 484         zend_string_release(str);
 485         return p->key;
 486 #else
 487         return str;
 488 #endif
 489 }
 490 
 491 #ifndef ZTS
 492 /* Copy PHP interned strings from PHP process memory into the shared memory */
 493 static void accel_use_shm_interned_strings(void)
 494 {
 495         uint idx, j;
 496         Bucket *p, *q;
 497 
 498         /* empty string */
 499         CG(empty_string) = accel_new_interned_string(CG(empty_string));
 500         for (j = 0; j < 256; j++) {
 501                 char s[2];
 502                 s[0] = j;
 503                 s[1] = 0;
 504                 CG(one_char_string)[j] = accel_new_interned_string(zend_string_init(s, 1, 0));
 505         }
 506 
 507         /* function table hash keys */
 508         for (idx = 0; idx < CG(function_table)->nNumUsed; idx++) {
 509                 p = CG(function_table)->arData + idx;
 510                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
 511                 if (p->key) {
 512                         p->key = accel_new_interned_string(p->key);
 513                 }
 514                 if (Z_FUNC(p->val)->common.function_name) {
 515                         Z_FUNC(p->val)->common.function_name = accel_new_interned_string(Z_FUNC(p->val)->common.function_name);
 516                 }
 517         }
 518 
 519         /* class table hash keys, class names, properties, methods, constants, etc */
 520         for (idx = 0; idx < CG(class_table)->nNumUsed; idx++) {
 521                 zend_class_entry *ce;
 522 
 523                 p = CG(class_table)->arData + idx;
 524                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
 525                 ce = (zend_class_entry*)Z_PTR(p->val);
 526 
 527                 if (p->key) {
 528                         p->key = accel_new_interned_string(p->key);
 529                 }
 530 
 531                 if (ce->name) {
 532                         ce->name = accel_new_interned_string(ce->name);
 533                 }
 534 
 535                 for (j = 0; j < ce->properties_info.nNumUsed; j++) {
 536                         zend_property_info *info;
 537 
 538                         q = ce->properties_info.arData + j;
 539                         if (Z_TYPE(q->val) == IS_UNDEF) continue;
 540 
 541                         info = (zend_property_info*)Z_PTR(q->val);
 542 
 543                         if (q->key) {
 544                                 q->key = accel_new_interned_string(q->key);
 545                         }
 546 
 547                         if (info->name) {
 548                                 info->name = accel_new_interned_string(info->name);
 549                         }
 550                 }
 551 
 552                 for (j = 0; j < ce->function_table.nNumUsed; j++) {
 553                         q = ce->function_table.arData + j;
 554                         if (Z_TYPE(q->val) == IS_UNDEF) continue;
 555                         if (q->key) {
 556                                 q->key = accel_new_interned_string(q->key);
 557                         }
 558                         if (Z_FUNC(q->val)->common.function_name) {
 559                                 Z_FUNC(q->val)->common.function_name = accel_new_interned_string(Z_FUNC(q->val)->common.function_name);
 560                         }
 561                 }
 562 
 563                 for (j = 0; j < ce->constants_table.nNumUsed; j++) {
 564                         q = ce->constants_table.arData + j;
 565                         if (!Z_TYPE(q->val) == IS_UNDEF) continue;
 566                         if (q->key) {
 567                                 q->key = accel_new_interned_string(q->key);
 568                         }
 569                 }
 570         }
 571 
 572         /* constant hash keys */
 573         for (idx = 0; idx < EG(zend_constants)->nNumUsed; idx++) {
 574                 p = EG(zend_constants)->arData + idx;
 575                 if (!Z_TYPE(p->val) == IS_UNDEF) continue;
 576                 if (p->key) {
 577                         p->key = accel_new_interned_string(p->key);
 578                 }
 579         }
 580 
 581         /* auto globals hash keys and names */
 582         for (idx = 0; idx < CG(auto_globals)->nNumUsed; idx++) {
 583                 zend_auto_global *auto_global;
 584 
 585                 p = CG(auto_globals)->arData + idx;
 586                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
 587 
 588                 auto_global = (zend_auto_global*)Z_PTR(p->val);;
 589 
 590                 zend_string_addref(auto_global->name);
 591                 auto_global->name = accel_new_interned_string(auto_global->name);
 592                 if (p->key) {
 593                         p->key = accel_new_interned_string(p->key);
 594                 }
 595         }
 596 }
 597 #endif
 598 
 599 #ifndef ZEND_WIN32
 600 static inline void kill_all_lockers(struct flock *mem_usage_check)
 601 {
 602         int tries = 10;
 603 
 604         /* so that other process won't try to force while we are busy cleaning up */
 605         ZCSG(force_restart_time) = 0;
 606         while (mem_usage_check->l_pid > 0) {
 607                 while (tries--) {
 608                         zend_accel_error(ACCEL_LOG_ERROR, "Killed locker %d", mem_usage_check->l_pid);
 609                         if (kill(mem_usage_check->l_pid, SIGKILL)) {
 610                                 break;
 611                         }
 612                         /* give it a chance to die */
 613                         usleep(20000);
 614                         if (kill(mem_usage_check->l_pid, 0)) {
 615                                 /* can't kill it */
 616                                 break;
 617                         }
 618                         usleep(10000);
 619                 }
 620                 if (!tries) {
 621                         zend_accel_error(ACCEL_LOG_ERROR, "Can't kill %d after 20 tries!", mem_usage_check->l_pid);
 622                         ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
 623                 }
 624 
 625                 mem_usage_check->l_type = F_WRLCK;
 626                 mem_usage_check->l_whence = SEEK_SET;
 627                 mem_usage_check->l_start = 1;
 628                 mem_usage_check->l_len = 1;
 629                 mem_usage_check->l_pid = -1;
 630                 if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
 631                         zend_accel_error(ACCEL_LOG_DEBUG, "KLockers:  %s (%d)", strerror(errno), errno);
 632                         break;
 633                 }
 634 
 635                 if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
 636                         break;
 637                 }
 638         }
 639 }
 640 #endif
 641 
 642 static inline int accel_is_inactive(void)
 643 {
 644 #ifdef ZEND_WIN32
 645         if (LOCKVAL(mem_usage) == 0) {
 646                 return SUCCESS;
 647         }
 648 #else
 649         FLOCK_STRUCTURE(mem_usage_check, F_WRLCK, SEEK_SET, 1, 1);
 650 
 651         mem_usage_check.l_pid = -1;
 652         if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
 653                 zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC:  %s (%d)", strerror(errno), errno);
 654                 return FAILURE;
 655         }
 656         if (mem_usage_check.l_type == F_UNLCK) {
 657                 return SUCCESS;
 658         }
 659 
 660         if (ZCG(accel_directives).force_restart_timeout
 661                 && ZCSG(force_restart_time)
 662                 && time(NULL) >= ZCSG(force_restart_time)) {
 663                 zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %d (after %d seconds), locked by %d", time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid);
 664                 kill_all_lockers(&mem_usage_check);
 665 
 666                 return FAILURE; /* next request should be able to restart it */
 667         }
 668 #endif
 669 
 670         return FAILURE;
 671 }
 672 
 673 static int zend_get_stream_timestamp(const char *filename, zend_stat_t *statbuf)
 674 {
 675         php_stream_wrapper *wrapper;
 676         php_stream_statbuf stream_statbuf;
 677         int ret, er;
 678 
 679         if (!filename) {
 680                 return FAILURE;
 681         }
 682 
 683         wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY);
 684         if (!wrapper) {
 685                 return FAILURE;
 686         }
 687         if (!wrapper->wops || !wrapper->wops->url_stat) {
 688                 statbuf->st_mtime = 1;
 689                 return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
 690         }
 691 
 692         er = EG(error_reporting);
 693         EG(error_reporting) = 0;
 694         zend_try {
 695                 ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL);
 696         } zend_catch {
 697                 ret = -1;
 698         } zend_end_try();
 699         EG(error_reporting) = er;
 700 
 701         if (ret != 0) {
 702                 return FAILURE;
 703         }
 704 
 705         *statbuf = stream_statbuf.sb;
 706         return SUCCESS;
 707 }
 708 
 709 #if ZEND_WIN32
 710 static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
 711 {
 712         static unsigned __int64 utc_base = 0;
 713         static FILETIME utc_base_ft;
 714         WIN32_FILE_ATTRIBUTE_DATA fdata;
 715 
 716         if (!file_handle->opened_path) {
 717                 return 0;
 718         }
 719 
 720         if (!utc_base) {
 721                 SYSTEMTIME st;
 722 
 723                 st.wYear = 1970;
 724                 st.wMonth = 1;
 725                 st.wDay = 1;
 726                 st.wHour = 0;
 727                 st.wMinute = 0;
 728                 st.wSecond = 0;
 729                 st.wMilliseconds = 0;
 730 
 731                 SystemTimeToFileTime (&st, &utc_base_ft);
 732                 utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
 733     }
 734 
 735         if (file_handle->opened_path && GetFileAttributesEx(file_handle->opened_path->val, GetFileExInfoStandard, &fdata) != 0) {
 736                 unsigned __int64 ftime;
 737 
 738                 if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
 739                         return 0;
 740                 }
 741 
 742                 ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
 743                 ftime /= 10000000L;
 744 
 745                 if (size) {
 746                         *size = (size_t)((((unsigned __int64)fdata.nFileSizeHigh) << 32) + (unsigned __int64)fdata.nFileSizeLow);
 747                 }
 748                 return (accel_time_t)ftime;
 749         }
 750         return 0;
 751 }
 752 #endif
 753 
 754 accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size)
 755 {
 756         zend_stat_t statbuf;
 757 #ifdef ZEND_WIN32
 758         accel_time_t res;
 759 #endif
 760 
 761         if (sapi_module.get_stat &&
 762             !EG(current_execute_data) &&
 763             file_handle->filename == SG(request_info).path_translated) {
 764 
 765                 zend_stat_t *tmpbuf = sapi_module.get_stat();
 766 
 767                 if (tmpbuf) {
 768                         if (size) {
 769                                 *size = tmpbuf->st_size;
 770                         }
 771                         return tmpbuf->st_mtime;
 772                 }
 773         }
 774 
 775 #ifdef ZEND_WIN32
 776         res = zend_get_file_handle_timestamp_win(file_handle, size);
 777         if (res) {
 778                 return res;
 779         }
 780 #endif
 781 
 782         switch (file_handle->type) {
 783                 case ZEND_HANDLE_FD:
 784                         if (zend_fstat(file_handle->handle.fd, &statbuf) == -1) {
 785                                 return 0;
 786                         }
 787                         break;
 788                 case ZEND_HANDLE_FP:
 789                         if (zend_fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
 790                                 if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
 791                                         return 0;
 792                                 }
 793                         }
 794                         break;
 795                 case ZEND_HANDLE_FILENAME:
 796                 case ZEND_HANDLE_MAPPED:
 797                         if (file_handle->opened_path) {
 798                                 char *file_path = ZSTR_VAL(file_handle->opened_path);
 799 
 800                                 if (is_stream_path(file_path)) {
 801                                         if (zend_get_stream_timestamp(file_path, &statbuf) == SUCCESS) {
 802                                                 break;
 803                                         }
 804                                 }
 805                                 if (VCWD_STAT(file_path, &statbuf) != -1) {
 806                                         break;
 807                                 }
 808                         }
 809 
 810                         if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
 811                                 return 0;
 812                         }
 813                         break;
 814                 case ZEND_HANDLE_STREAM:
 815                         {
 816                                 php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
 817                                 php_stream_statbuf sb;
 818                                 int ret, er;
 819 
 820                                 if (!stream ||
 821                                     !stream->ops ||
 822                                     !stream->ops->stat) {
 823                                         return 0;
 824                                 }
 825 
 826                                 er = EG(error_reporting);
 827                                 EG(error_reporting) = 0;
 828                                 zend_try {
 829                                         ret = stream->ops->stat(stream, &sb);
 830                                 } zend_catch {
 831                                         ret = -1;
 832                                 } zend_end_try();
 833                                 EG(error_reporting) = er;
 834                                 if (ret != 0) {
 835                                         return 0;
 836                                 }
 837 
 838                                 statbuf = sb.sb;
 839                         }
 840                         break;
 841 
 842                 default:
 843                         return 0;
 844         }
 845 
 846         if (size) {
 847                 *size = statbuf.st_size;
 848         }
 849         return statbuf.st_mtime;
 850 }
 851 
 852 static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
 853 {
 854         zend_file_handle ps_handle;
 855         zend_string *full_path_ptr = NULL;
 856 
 857         /** check that the persistent script is indeed the same file we cached
 858          * (if part of the path is a symlink than it possible that the user will change it)
 859          * See bug #15140
 860          */
 861         if (file_handle->opened_path) {
 862                 if (persistent_script->full_path != file_handle->opened_path &&
 863                     (ZSTR_LEN(persistent_script->full_path) != ZSTR_LEN(file_handle->opened_path) ||
 864                      memcmp(ZSTR_VAL(persistent_script->full_path), ZSTR_VAL(file_handle->opened_path), ZSTR_LEN(file_handle->opened_path)) != 0)) {
 865                         return FAILURE;
 866                 }
 867         } else {
 868                 full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename, strlen(file_handle->filename));
 869                 if (full_path_ptr &&
 870                     persistent_script->full_path != full_path_ptr &&
 871                     (ZSTR_LEN(persistent_script->full_path) != ZSTR_LEN(full_path_ptr) ||
 872                      memcmp(ZSTR_VAL(persistent_script->full_path), ZSTR_VAL(full_path_ptr), ZSTR_LEN(full_path_ptr)) != 0)) {
 873                         zend_string_release(full_path_ptr);
 874                         return FAILURE;
 875                 }
 876                 file_handle->opened_path = full_path_ptr;
 877         }
 878 
 879         if (persistent_script->timestamp == 0) {
 880                 if (full_path_ptr) {
 881                         zend_string_release(full_path_ptr);
 882                         file_handle->opened_path = NULL;
 883                 }
 884                 return FAILURE;
 885         }
 886 
 887         if (zend_get_file_handle_timestamp(file_handle, NULL) == persistent_script->timestamp) {
 888                 if (full_path_ptr) {
 889                         zend_string_release(full_path_ptr);
 890                         file_handle->opened_path = NULL;
 891                 }
 892                 return SUCCESS;
 893         }
 894         if (full_path_ptr) {
 895                 zend_string_release(full_path_ptr);
 896                 file_handle->opened_path = NULL;
 897         }
 898 
 899         ps_handle.type = ZEND_HANDLE_FILENAME;
 900         ps_handle.filename = ZSTR_VAL(persistent_script->full_path);
 901         ps_handle.opened_path = persistent_script->full_path;
 902 
 903         if (zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp) {
 904                 return SUCCESS;
 905         }
 906 
 907         return FAILURE;
 908 }
 909 
 910 int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
 911 {
 912         if (ZCG(accel_directives).revalidate_freq &&
 913             persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
 914                 return SUCCESS;
 915         } else if (do_validate_timestamps(persistent_script, file_handle) == FAILURE) {
 916                 return FAILURE;
 917         } else {
 918                 persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
 919                 return SUCCESS;
 920         }
 921 }
 922 
 923 /* Instead of resolving full real path name each time we need to identify file,
 924  * we create a key that consist from requested file name, current working
 925  * directory, current include_path, etc */
 926 char *accel_make_persistent_key(const char *path, int path_length, int *key_len)
 927 {
 928         int key_length;
 929 
 930         /* CWD and include_path don't matter for absolute file names and streams */
 931     if (IS_ABSOLUTE_PATH(path, path_length)) {
 932                 /* pass */
 933                 ZCG(key_len) = 0;
 934     } else if (UNEXPECTED(is_stream_path(path))) {
 935                 if (!is_cacheable_stream_path(path)) {
 936                         return NULL;
 937                 }
 938                 /* pass */
 939                 ZCG(key_len) = 0;
 940     } else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
 941                 /* pass */
 942                 ZCG(key_len) = 0;
 943     } else {
 944                 const char *include_path = NULL, *cwd = NULL;
 945                 int include_path_len = 0, cwd_len = 0;
 946                 zend_string *parent_script = NULL;
 947                 size_t parent_script_len = 0;
 948 
 949                 if (EXPECTED(ZCG(cwd_key_len))) {
 950                         cwd = ZCG(cwd_key);
 951                         cwd_len = ZCG(cwd_key_len);
 952                 } else {
 953                         zend_string *cwd_str = accel_getcwd();
 954 
 955                         if (UNEXPECTED(!cwd_str)) {
 956                                 /* we don't handle this well for now. */
 957                                 zend_accel_error(ACCEL_LOG_INFO, "getcwd() failed for '%s' (%d), please try to set opcache.use_cwd to 0 in ini file", path, errno);
 958                                 return NULL;
 959                         }
 960                         cwd = ZSTR_VAL(cwd_str);
 961                         cwd_len = ZSTR_LEN(cwd_str);
 962 #ifndef ZTS
 963                         if (ZCG(cwd_check)) {
 964                                 ZCG(cwd_check) = 0;
 965                                 if ((ZCG(counted) || ZCSG(accelerator_enabled))) {
 966 
 967                                         zend_string *str = accel_find_interned_string(cwd_str);
 968                                         if (!str) {
 969                                                 SHM_UNPROTECT();
 970                                                 zend_shared_alloc_lock();
 971                                                 str = accel_new_interned_string(zend_string_copy(cwd_str));
 972                                                 if (str == cwd_str) {
 973                                                         zend_string_release(str);
 974                                                         str = NULL;
 975                                                 }
 976                                                 zend_shared_alloc_unlock();
 977                                                 SHM_PROTECT();
 978                                         }
 979                                         if (str) {
 980                                                 char buf[32];
 981                                                 char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, ZSTR_VAL(str) - ZCSG(interned_strings_start));
 982 
 983                                                 cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
 984                                                 cwd = ZCG(cwd_key);
 985                                                 memcpy(ZCG(cwd_key), res, cwd_len + 1);
 986                                         }
 987                                 }
 988                         }
 989 #endif
 990                 }
 991 
 992                 if (EXPECTED(ZCG(include_path_key_len))) {
 993                         include_path = ZCG(include_path_key);
 994                         include_path_len = ZCG(include_path_key_len);
 995                 } else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
 996                         include_path = "";
 997                         include_path_len = 0;
 998                 } else {
 999                         include_path = ZSTR_VAL(ZCG(include_path));
1000                         include_path_len = ZSTR_LEN(ZCG(include_path));
1001 
1002 #ifndef ZTS
1003                         if (ZCG(include_path_check)) {
1004                                 ZCG(include_path_check) = 0;
1005                                 if ((ZCG(counted) || ZCSG(accelerator_enabled))) {
1006 
1007                                         zend_string *str = accel_find_interned_string(ZCG(include_path));
1008                                         if (!str) {
1009                                                 SHM_UNPROTECT();
1010                                                 zend_shared_alloc_lock();
1011                                                 str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
1012                                                 if (str == ZCG(include_path)) {
1013                                                         str = NULL;
1014                                                 }
1015                                                 zend_shared_alloc_unlock();
1016                                                 SHM_PROTECT();
1017                                         }
1018                                         if (str) {
1019                                                 char buf[32];
1020                                                 char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, ZSTR_VAL(str) - ZCSG(interned_strings_start));
1021 
1022                                                 include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
1023                                                 include_path = ZCG(include_path_key);
1024                                                 memcpy(ZCG(include_path_key), res, include_path_len + 1);
1025                                         }
1026                                 }
1027                         }
1028 #endif
1029                 }
1030 
1031                 /* Calculate key length */
1032                 if (UNEXPECTED((size_t)(cwd_len + path_length + include_path_len + 2) >= sizeof(ZCG(key)))) {
1033                         return NULL;
1034                 }
1035 
1036                 /* Generate key
1037                  * Note - the include_path must be the last element in the key,
1038                  * since in itself, it may include colons (which we use to separate
1039                  * different components of the key)
1040                  */
1041                 memcpy(ZCG(key), path, path_length);
1042                 ZCG(key)[path_length] = ':';
1043                 key_length = path_length + 1;
1044                 memcpy(ZCG(key) + key_length, cwd, cwd_len);
1045                 key_length += cwd_len;
1046 
1047                 if (include_path_len) {
1048                         ZCG(key)[key_length] = ':';
1049                         key_length += 1;
1050                         memcpy(ZCG(key) + key_length, include_path, include_path_len);
1051                         key_length += include_path_len;
1052                 }
1053 
1054                 /* Here we add to the key the parent script directory,
1055                  * since fopen_wrappers from version 4.0.7 use current script's path
1056                  * in include path too.
1057                  */
1058                 if (EXPECTED(EG(current_execute_data)) &&
1059                     EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
1060 
1061                         parent_script_len = ZSTR_LEN(parent_script);
1062                         while ((--parent_script_len > 0) && !IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len]));
1063 
1064                         if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= sizeof(ZCG(key)))) {
1065                                 return NULL;
1066                         }
1067                         ZCG(key)[key_length] = ':';
1068                         key_length += 1;
1069                         memcpy(ZCG(key) + key_length, ZSTR_VAL(parent_script), parent_script_len);
1070                         key_length += parent_script_len;
1071                 }
1072                 ZCG(key)[key_length] = '\0';
1073                 *key_len = ZCG(key_len) = key_length;
1074                 return ZCG(key);
1075         }
1076 
1077         /* not use_cwd */
1078         *key_len = path_length;
1079         return (char*)path;
1080 }
1081 
1082 int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force)
1083 {
1084         zend_string *realpath;
1085         zend_persistent_script *persistent_script;
1086 
1087         if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
1088                 return FAILURE;
1089         }
1090 
1091         realpath = accelerator_orig_zend_resolve_path(filename, filename_len);
1092 
1093         if (!realpath) {
1094                 return FAILURE;
1095         }
1096 
1097 #ifdef HAVE_OPCACHE_FILE_CACHE
1098         if (ZCG(accel_directives).file_cache) {
1099                 zend_file_cache_invalidate(realpath);
1100         }
1101 #endif
1102 
1103         persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
1104         if (persistent_script && !persistent_script->corrupted) {
1105                 zend_file_handle file_handle;
1106 
1107                 file_handle.type = ZEND_HANDLE_FILENAME;
1108                 file_handle.filename = ZSTR_VAL(realpath);
1109                 file_handle.opened_path = realpath;
1110 
1111                 if (force ||
1112                         !ZCG(accel_directives).validate_timestamps ||
1113                         do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
1114                         SHM_UNPROTECT();
1115                         zend_shared_alloc_lock();
1116                         if (!persistent_script->corrupted) {
1117                                 persistent_script->corrupted = 1;
1118                                 persistent_script->timestamp = 0;
1119                                 ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1120                                 if (ZSMMG(memory_exhausted)) {
1121                                         zend_accel_restart_reason reason =
1122                                                 zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1123                                         zend_accel_schedule_restart_if_necessary(reason);
1124                                 }
1125                         }
1126                         zend_shared_alloc_unlock();
1127                         SHM_PROTECT();
1128                 }
1129         }
1130 
1131         accelerator_shm_read_unlock();
1132         zend_string_release(realpath);
1133 
1134         return SUCCESS;
1135 }
1136 
1137 /* Adds another key for existing cached script */
1138 static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_hash_entry *bucket)
1139 {
1140         if (!zend_accel_hash_str_find(&ZCSG(hash), key, key_length)) {
1141                 if (zend_accel_hash_is_full(&ZCSG(hash))) {
1142                         zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1143                         ZSMMG(memory_exhausted) = 1;
1144                         zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1145                 } else {
1146                         char *new_key = zend_shared_alloc(key_length + 1);
1147                         if (new_key) {
1148                                 memcpy(new_key, key, key_length + 1);
1149                                 if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length, 1, bucket)) {
1150                                         zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key);
1151                                 }
1152                         } else {
1153                                 zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1154                         }
1155                 }
1156         }
1157 }
1158 
1159 #ifdef HAVE_OPCACHE_FILE_CACHE
1160 static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script *new_persistent_script, int *from_shared_memory)
1161 {
1162         uint memory_used;
1163 
1164         /* Check if script may be stored in shared memory */
1165         if (!zend_accel_script_persistable(new_persistent_script)) {
1166                 return new_persistent_script;
1167         }
1168 
1169         if (!zend_accel_script_optimize(new_persistent_script)) {
1170                 return new_persistent_script;
1171         }
1172 
1173         zend_shared_alloc_init_xlat_table();
1174 
1175         /* Calculate the required memory size */
1176         memory_used = zend_accel_script_persist_calc(new_persistent_script, NULL, 0);
1177 
1178         /* Allocate memory block */
1179 #ifdef __SSE2__
1180         /* Align to 64-byte boundary */
1181         ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 64);
1182         ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
1183 #else
1184         ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used);
1185 #endif
1186 
1187         /* Copy into shared memory */
1188         new_persistent_script = zend_accel_script_persist(new_persistent_script, NULL, 0);
1189 
1190         zend_shared_alloc_destroy_xlat_table();
1191 
1192         new_persistent_script->is_phar =
1193                 new_persistent_script->full_path &&
1194                 strstr(ZSTR_VAL(new_persistent_script->full_path), ".phar") &&
1195                 !strstr(ZSTR_VAL(new_persistent_script->full_path), "://");
1196 
1197         /* Consistency check */
1198         if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
1199                 zend_accel_error(
1200                         ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
1201                         "Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
1202                         ZSTR_VAL(new_persistent_script->full_path),
1203                         new_persistent_script->mem,
1204                         (char *)new_persistent_script->mem + new_persistent_script->size,
1205                         ZCG(mem));
1206         }
1207 
1208         new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
1209 
1210         zend_file_cache_script_store(new_persistent_script, 0);
1211 
1212         *from_shared_memory = 1;
1213         return new_persistent_script;
1214 }
1215 #endif
1216 
1217 static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length, int *from_shared_memory)
1218 {
1219         zend_accel_hash_entry *bucket;
1220         uint memory_used;
1221 
1222         /* Check if script may be stored in shared memory */
1223         if (!zend_accel_script_persistable(new_persistent_script)) {
1224                 return new_persistent_script;
1225         }
1226 
1227         if (!zend_accel_script_optimize(new_persistent_script)) {
1228                 return new_persistent_script;
1229         }
1230 
1231         /* exclusive lock */
1232         zend_shared_alloc_lock();
1233 
1234         if (zend_accel_hash_is_full(&ZCSG(hash))) {
1235                 zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1236                 ZSMMG(memory_exhausted) = 1;
1237                 zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1238                 zend_shared_alloc_unlock();
1239                 return new_persistent_script;
1240         }
1241 
1242         /* Check if we still need to put the file into the cache (may be it was
1243          * already stored by another process. This final check is done under
1244          * exclusive lock) */
1245         bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->full_path);
1246         if (bucket) {
1247                 zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
1248 
1249                 if (!existing_persistent_script->corrupted) {
1250                         if (key &&
1251                             (!ZCG(accel_directives).validate_timestamps ||
1252                              (new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
1253                                 zend_accel_add_key(key, key_length, bucket);
1254                         }
1255                         zend_shared_alloc_unlock();
1256                         return new_persistent_script;
1257                 }
1258         }
1259 
1260 
1261         zend_shared_alloc_init_xlat_table();
1262 
1263         /* Calculate the required memory size */
1264         memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length);
1265 
1266         /* Allocate shared memory */
1267 #ifdef __SSE2__
1268         /* Align to 64-byte boundary */
1269         ZCG(mem) = zend_shared_alloc(memory_used + 64);
1270         ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
1271 #else
1272         ZCG(mem) = zend_shared_alloc(memory_used);
1273 #endif
1274         if (!ZCG(mem)) {
1275                 zend_shared_alloc_destroy_xlat_table();
1276                 zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1277                 zend_shared_alloc_unlock();
1278                 return new_persistent_script;
1279         }
1280 
1281         /* Copy into shared memory */
1282         new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length);
1283 
1284         zend_shared_alloc_destroy_xlat_table();
1285 
1286         new_persistent_script->is_phar =
1287                 new_persistent_script->full_path &&
1288                 strstr(ZSTR_VAL(new_persistent_script->full_path), ".phar") &&
1289                 !strstr(ZSTR_VAL(new_persistent_script->full_path), "://");
1290 
1291         /* Consistency check */
1292         if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
1293                 zend_accel_error(
1294                         ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
1295                         "Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
1296                         ZSTR_VAL(new_persistent_script->full_path),
1297                         new_persistent_script->mem,
1298                         (char *)new_persistent_script->mem + new_persistent_script->size,
1299                         ZCG(mem));
1300         }
1301 
1302         new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
1303 
1304         /* store script structure in the hash table */
1305         bucket = zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(new_persistent_script->full_path), ZSTR_LEN(new_persistent_script->full_path), 0, new_persistent_script);
1306         if (bucket) {
1307                 zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", new_persistent_script->full_path);
1308                 if (key &&
1309                     /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
1310                     memcmp(key, "phar://", sizeof("phar://") - 1) != 0 &&
1311                     (ZSTR_LEN(new_persistent_script->full_path) != key_length ||
1312                      memcmp(ZSTR_VAL(new_persistent_script->full_path), key, key_length) != 0)) {
1313                         /* link key to the same persistent script in hash table */
1314                         if (zend_accel_hash_update(&ZCSG(hash), key, key_length, 1, bucket)) {
1315                                 zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", key);
1316                         } else {
1317                                 zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1318                                 ZSMMG(memory_exhausted) = 1;
1319                                 zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1320                         }
1321                 }
1322         }
1323 
1324         new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
1325 
1326         zend_shared_alloc_unlock();
1327 
1328 #ifdef HAVE_OPCACHE_FILE_CACHE
1329         if (ZCG(accel_directives).file_cache) {
1330                 SHM_PROTECT();
1331                 zend_file_cache_script_store(new_persistent_script, 1);
1332                 SHM_UNPROTECT();
1333         }
1334 #endif
1335 
1336         *from_shared_memory = 1;
1337         return new_persistent_script;
1338 }
1339 
1340 static const struct jit_auto_global_info
1341 {
1342     const char *name;
1343     size_t len;
1344 } jit_auto_globals_info[] = {
1345     { "_SERVER",  sizeof("_SERVER")-1},
1346     { "_ENV",     sizeof("_ENV")-1},
1347     { "_REQUEST", sizeof("_REQUEST")-1},
1348     { "GLOBALS",  sizeof("GLOBALS")-1},
1349 };
1350 
1351 static zend_string *jit_auto_globals_str[4];
1352 
1353 static int zend_accel_get_auto_globals(void)
1354 {
1355         int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1356         int n = 1;
1357         int mask = 0;
1358 
1359         for (i = 0; i < ag_size ; i++) {
1360                 if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_str[i])) {
1361                         mask |= n;
1362                 }
1363                 n += n;
1364         }
1365         return mask;
1366 }
1367 
1368 static int zend_accel_get_auto_globals_no_jit(void)
1369 {
1370         if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_str[3])) {
1371                 return 8;
1372         }
1373         return 0;
1374 }
1375 
1376 static void zend_accel_set_auto_globals(int mask)
1377 {
1378         int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1379         int n = 1;
1380 
1381         for (i = 0; i < ag_size ; i++) {
1382                 if ((mask & n) && !(ZCG(auto_globals_mask) & n)) {
1383                         ZCG(auto_globals_mask) |= n;
1384                         zend_is_auto_global(jit_auto_globals_str[i]);
1385                 }
1386                 n += n;
1387         }
1388 }
1389 
1390 static void zend_accel_init_auto_globals(void)
1391 {
1392         int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1393 
1394         for (i = 0; i < ag_size ; i++) {
1395                 jit_auto_globals_str[i] = zend_string_init(jit_auto_globals_info[i].name, jit_auto_globals_info[i].len, 1);
1396                 zend_string_hash_val(jit_auto_globals_str[i]);
1397                 jit_auto_globals_str[i] = accel_new_interned_string(jit_auto_globals_str[i]);
1398         }
1399 }
1400 
1401 static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, char *key, unsigned int key_length, zend_op_array **op_array_p)
1402 {
1403         zend_persistent_script *new_persistent_script;
1404         zend_op_array *orig_active_op_array;
1405         HashTable *orig_function_table, *orig_class_table;
1406         zval orig_user_error_handler;
1407         zend_op_array *op_array;
1408         int do_bailout = 0;
1409         accel_time_t timestamp = 0;
1410         uint32_t orig_compiler_options = 0;
1411 
1412     /* Try to open file */
1413     if (file_handle->type == ZEND_HANDLE_FILENAME) {
1414         if (accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == SUCCESS) {
1415                 /* key may be changed by zend_stream_open_function() */
1416                 if (key == ZCG(key)) {
1417                         key_length = ZCG(key_len);
1418                 }
1419         } else {
1420                         *op_array_p = NULL;
1421                         if (type == ZEND_REQUIRE) {
1422                                 zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
1423                                 zend_bailout();
1424                         } else {
1425                                 zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
1426                         }
1427                         return NULL;
1428         }
1429     }
1430 
1431         /* check blacklist right after ensuring that file was opened */
1432         if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, ZSTR_VAL(file_handle->opened_path))) {
1433                 ZCSG(blacklist_misses)++;
1434                 *op_array_p = accelerator_orig_compile_file(file_handle, type);
1435                 return NULL;
1436         }
1437 
1438         if (ZCG(accel_directives).validate_timestamps ||
1439             ZCG(accel_directives).file_update_protection ||
1440             ZCG(accel_directives).max_file_size > 0) {
1441                 size_t size = 0;
1442 
1443                 /* Obtain the file timestamps, *before* actually compiling them,
1444                  * otherwise we have a race-condition.
1445                  */
1446                 timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL);
1447 
1448                 /* If we can't obtain a timestamp (that means file is possibly socket)
1449                  *  we won't cache it
1450                  */
1451                 if (timestamp == 0) {
1452                         *op_array_p = accelerator_orig_compile_file(file_handle, type);
1453                         return NULL;
1454                 }
1455 
1456                 /* check if file is too new (may be it's not written completely yet) */
1457                 if (ZCG(accel_directives).file_update_protection &&
1458                     (ZCG(request_time) - ZCG(accel_directives).file_update_protection < timestamp)) {
1459                         *op_array_p = accelerator_orig_compile_file(file_handle, type);
1460                         return NULL;
1461                 }
1462 
1463                 if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
1464                         ZCSG(blacklist_misses)++;
1465                         *op_array_p = accelerator_orig_compile_file(file_handle, type);
1466                         return NULL;
1467                 }
1468         }
1469 
1470         new_persistent_script = create_persistent_script();
1471 
1472         /* Save the original values for the op_array, function table and class table */
1473         orig_active_op_array = CG(active_op_array);
1474         orig_function_table = CG(function_table);
1475         orig_class_table = CG(class_table);
1476         ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
1477 
1478         /* Override them with ours */
1479         CG(function_table) = &ZCG(function_table);
1480         EG(class_table) = CG(class_table) = &new_persistent_script->class_table;
1481         ZVAL_UNDEF(&EG(user_error_handler));
1482 
1483         zend_try {
1484                 orig_compiler_options = CG(compiler_options);
1485                 CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
1486                 CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
1487                 CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
1488                 CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
1489                 op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
1490                 CG(compiler_options) = orig_compiler_options;
1491         } zend_catch {
1492                 op_array = NULL;
1493                 do_bailout = 1;
1494                 CG(compiler_options) = orig_compiler_options;
1495         } zend_end_try();
1496 
1497         /* Restore originals */
1498         CG(active_op_array) = orig_active_op_array;
1499         CG(function_table) = orig_function_table;
1500         EG(class_table) = CG(class_table) = orig_class_table;
1501         EG(user_error_handler) = orig_user_error_handler;
1502 
1503         if (!op_array) {
1504                 /* compilation failed */
1505                 free_persistent_script(new_persistent_script, 1);
1506                 zend_accel_free_user_functions(&ZCG(function_table));
1507                 if (do_bailout) {
1508                         zend_bailout();
1509                 }
1510                 return NULL;
1511         }
1512 
1513         /* Build the persistent_script structure.
1514            Here we aren't sure we would store it, but we will need it
1515            further anyway.
1516         */
1517         zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->function_table);
1518         new_persistent_script->main_op_array = *op_array;
1519 
1520         efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
1521 
1522     /* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
1523        will have to ping the used auto global variables before execution */
1524         if (PG(auto_globals_jit)) {
1525                 new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
1526         } else {
1527                 new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals_no_jit();
1528         }
1529 
1530         if (ZCG(accel_directives).validate_timestamps) {
1531                 /* Obtain the file timestamps, *before* actually compiling them,
1532                  * otherwise we have a race-condition.
1533                  */
1534                 new_persistent_script->timestamp = timestamp;
1535                 new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1536         }
1537 
1538         if (file_handle->opened_path) {
1539                 new_persistent_script->full_path = zend_string_copy(file_handle->opened_path);
1540         } else {
1541                 new_persistent_script->full_path = zend_string_init(file_handle->filename, strlen(file_handle->filename), 0);
1542         }
1543         zend_string_hash_val(new_persistent_script->full_path);
1544 
1545         /* Now persistent_script structure is ready in process memory */
1546         return new_persistent_script;
1547 }
1548 
1549 #ifdef HAVE_OPCACHE_FILE_CACHE
1550 zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
1551 {
1552         zend_persistent_script *persistent_script;
1553         zend_op_array *op_array = NULL;
1554         int from_memory; /* if the script we've got is stored in SHM */
1555 
1556         if (is_stream_path(file_handle->filename) &&
1557             !is_cacheable_stream_path(file_handle->filename)) {
1558                 return accelerator_orig_compile_file(file_handle, type);
1559         }
1560 
1561         if (!file_handle->opened_path) {
1562                 if (file_handle->type == ZEND_HANDLE_FILENAME &&
1563                     accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
1564                         if (type == ZEND_REQUIRE) {
1565                                 zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
1566                                 zend_bailout();
1567                         } else {
1568                                 zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
1569                         }
1570                         return NULL;
1571             }
1572         }
1573 
1574         SHM_UNPROTECT();
1575         persistent_script = zend_file_cache_script_load(file_handle);
1576         SHM_PROTECT();
1577         if (persistent_script) {
1578                 /* see bug #15471 (old BTS) */
1579                 if (persistent_script->full_path) {
1580                         if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
1581                             !EG(current_execute_data)->func ||
1582                             !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
1583                             EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
1584                             (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
1585                              EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
1586                                 if (zend_hash_add_empty_element(&EG(included_files), persistent_script->full_path) != NULL) {
1587                                         /* ext/phar has to load phar's metadata into memory */
1588                                         if (persistent_script->is_phar) {
1589                                                 php_stream_statbuf ssb;
1590                                                 char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->full_path));
1591 
1592                                                 memcpy(fname, "phar://", sizeof("phar://") - 1);
1593                                                 memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->full_path), ZSTR_LEN(persistent_script->full_path) + 1);
1594                                                 php_stream_stat_path(fname, &ssb);
1595                                                 efree(fname);
1596                                         }
1597                                 }
1598                         }
1599                 }
1600                 zend_file_handle_dtor(file_handle);
1601 
1602             if (persistent_script->ping_auto_globals_mask) {
1603                         zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
1604                 }
1605 
1606                 return zend_accel_load_script(persistent_script, 1);
1607         }
1608 
1609         persistent_script = opcache_compile_file(file_handle, type, NULL, 0, &op_array);
1610 
1611         if (persistent_script) {
1612                 from_memory = 0;
1613                 persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
1614                 return zend_accel_load_script(persistent_script, from_memory);
1615         }
1616 
1617         return op_array;
1618 }
1619 #endif
1620 
1621 /* zend_compile() replacement */
1622 zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
1623 {
1624         zend_persistent_script *persistent_script = NULL;
1625         char *key = NULL;
1626         int key_length;
1627         int from_shared_memory; /* if the script we've got is stored in SHM */
1628 
1629         if (!file_handle->filename || !ZCG(enabled) || !accel_startup_ok) {
1630                 /* The Accelerator is disabled, act as if without the Accelerator */
1631                 return accelerator_orig_compile_file(file_handle, type);
1632 #ifdef HAVE_OPCACHE_FILE_CACHE
1633         } else if (ZCG(accel_directives).file_cache_only) {
1634                 return file_cache_compile_file(file_handle, type);
1635 #endif
1636         } else if ((!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
1637                    (ZCSG(restart_in_progress) && accel_restart_is_active())) {
1638 #ifdef HAVE_OPCACHE_FILE_CACHE
1639                 if (ZCG(accel_directives).file_cache) {
1640                         return file_cache_compile_file(file_handle, type);
1641                 }
1642 #endif
1643                 return accelerator_orig_compile_file(file_handle, type);
1644         }
1645 
1646         /* In case this callback is called from include_once, require_once or it's
1647          * a main FastCGI request, the key must be already calculated, and cached
1648          * persistent script already found */
1649         if (ZCG(cache_persistent_script) &&
1650             ((!EG(current_execute_data) &&
1651               file_handle->filename == SG(request_info).path_translated &&
1652               ZCG(cache_opline) == NULL) ||
1653              (EG(current_execute_data) &&
1654               EG(current_execute_data)->func &&
1655               ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1656               ZCG(cache_opline) == EG(current_execute_data)->opline))) {
1657 
1658                 persistent_script = ZCG(cache_persistent_script);
1659                 if (ZCG(key_len)) {
1660                         key = ZCG(key);
1661                         key_length = ZCG(key_len);
1662                 }
1663 
1664         } else {
1665                 if (!ZCG(accel_directives).revalidate_path) {
1666                         /* try to find cached script by key */
1667                         key = accel_make_persistent_key(file_handle->filename, strlen(file_handle->filename), &key_length);
1668                         if (!key) {
1669                                 return accelerator_orig_compile_file(file_handle, type);
1670                         }
1671                         persistent_script = zend_accel_hash_str_find(&ZCSG(hash), key, key_length);
1672                 }
1673                 if (!persistent_script) {
1674                         /* try to find cached script by full real path */
1675                         zend_accel_hash_entry *bucket;
1676 
1677                         /* open file to resolve the path */
1678                     if (file_handle->type == ZEND_HANDLE_FILENAME &&
1679                         accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
1680                                 if (type == ZEND_REQUIRE) {
1681                                         zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
1682                                         zend_bailout();
1683                                 } else {
1684                                         zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
1685                                 }
1686                                 return NULL;
1687                     }
1688 
1689                         if (file_handle->opened_path) {
1690                                 bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
1691 
1692                                 if (bucket) {
1693                                         persistent_script = (zend_persistent_script *)bucket->data;
1694 
1695                                         if (key && !persistent_script->corrupted) {
1696                                                 SHM_UNPROTECT();
1697                                                 zend_shared_alloc_lock();
1698                                                 zend_accel_add_key(key, key_length, bucket);
1699                                                 zend_shared_alloc_unlock();
1700                                                 SHM_PROTECT();
1701                                         }
1702                                 }
1703                         }
1704                 }
1705         }
1706 
1707         /* clear cache */
1708         ZCG(cache_opline) = NULL;
1709         ZCG(cache_persistent_script) = NULL;
1710 
1711         if (persistent_script && persistent_script->corrupted) {
1712                 persistent_script = NULL;
1713         }
1714 
1715         /* Make sure we only increase the currently running processes semaphore
1716      * once each execution (this function can be called more than once on
1717      * each execution)
1718      */
1719         if (!ZCG(counted)) {
1720                 if (accel_activate_add() == FAILURE) {
1721 #ifdef HAVE_OPCACHE_FILE_CACHE
1722                         if (ZCG(accel_directives).file_cache) {
1723                                 return file_cache_compile_file(file_handle, type);
1724                         }
1725 #endif
1726                         return accelerator_orig_compile_file(file_handle, type);
1727                 }
1728                 ZCG(counted) = 1;
1729         }
1730 
1731         SHM_UNPROTECT();
1732 
1733         /* If script is found then validate_timestamps if option is enabled */
1734         if (persistent_script && ZCG(accel_directives).validate_timestamps) {
1735                 if (validate_timestamp_and_record(persistent_script, file_handle) == FAILURE) {
1736                         zend_shared_alloc_lock();
1737                         if (!persistent_script->corrupted) {
1738                                 persistent_script->corrupted = 1;
1739                                 persistent_script->timestamp = 0;
1740                                 ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1741                                 if (ZSMMG(memory_exhausted)) {
1742                                         zend_accel_restart_reason reason =
1743                                                 zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1744                                         zend_accel_schedule_restart_if_necessary(reason);
1745                                 }
1746                         }
1747                         zend_shared_alloc_unlock();
1748                         persistent_script = NULL;
1749                 }
1750         }
1751 
1752         /* if turned on - check the compiled script ADLER32 checksum */
1753         if (persistent_script && ZCG(accel_directives).consistency_checks
1754                 && persistent_script->dynamic_members.hits % ZCG(accel_directives).consistency_checks == 0) {
1755 
1756                 unsigned int checksum = zend_accel_script_checksum(persistent_script);
1757                 if (checksum != persistent_script->dynamic_members.checksum ) {
1758                         /* The checksum is wrong */
1759                         zend_accel_error(ACCEL_LOG_INFO, "Checksum failed for '%s':  expected=0x%0.8X, found=0x%0.8X",
1760                                                          persistent_script->full_path, persistent_script->dynamic_members.checksum, checksum);
1761                         zend_shared_alloc_lock();
1762                         if (!persistent_script->corrupted) {
1763                                 persistent_script->corrupted = 1;
1764                                 persistent_script->timestamp = 0;
1765                                 ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1766                                 if (ZSMMG(memory_exhausted)) {
1767                                         zend_accel_restart_reason reason =
1768                                                 zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1769                                         zend_accel_schedule_restart_if_necessary(reason);
1770                                 }
1771                         }
1772                         zend_shared_alloc_unlock();
1773                         persistent_script = NULL;
1774                 }
1775         }
1776 
1777 #ifdef HAVE_OPCACHE_FILE_CACHE
1778         /* Check the second level cache */
1779         if (!persistent_script && ZCG(accel_directives).file_cache) {
1780                 persistent_script = zend_file_cache_script_load(file_handle);
1781         }
1782 #endif
1783 
1784         /* If script was not found or invalidated by validate_timestamps */
1785         if (!persistent_script) {
1786                 uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
1787                 zend_op_array *op_array;
1788 
1789                 /* Cache miss.. */
1790                 ZCSG(misses)++;
1791 
1792                 /* No memory left. Behave like without the Accelerator */
1793                 if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
1794                         SHM_PROTECT();
1795                         return accelerator_orig_compile_file(file_handle, type);
1796                 }
1797 
1798                 /* Try and cache the script and assume that it is returned from_shared_memory.
1799          * If it isn't compile_and_cache_file() changes the flag to 0
1800          */
1801         from_shared_memory = 0;
1802                 persistent_script = opcache_compile_file(file_handle, type, key, key ? key_length : 0, &op_array);
1803                 if (persistent_script) {
1804                         persistent_script = cache_script_in_shared_memory(persistent_script, key, key ? key_length : 0, &from_shared_memory);
1805                 }
1806 
1807                 /* Caching is disabled, returning op_array;
1808                  * or something went wrong during compilation, returning NULL
1809                  */
1810                 if (!persistent_script) {
1811                         SHM_PROTECT();
1812                         return op_array;
1813                 }
1814                 if (from_shared_memory) {
1815                         /* Delete immutable arrays moved into SHM */
1816                         uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
1817                         while (new_const_num > old_const_num) {
1818                                 new_const_num--;
1819                                 zend_hash_index_del(EG(zend_constants), new_const_num);
1820                         }
1821                 }
1822         } else {
1823 
1824 #if !ZEND_WIN32
1825                 ZCSG(hits)++; /* TBFixed: may lose one hit */
1826                 persistent_script->dynamic_members.hits++; /* see above */
1827 #else
1828 #ifdef _M_X64
1829                 InterlockedIncrement64(&ZCSG(hits));
1830 #else
1831                 InterlockedIncrement(&ZCSG(hits));
1832 #endif
1833                 InterlockedIncrement64(&persistent_script->dynamic_members.hits);
1834 #endif
1835 
1836                 /* see bug #15471 (old BTS) */
1837                 if (persistent_script->full_path) {
1838                         if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
1839                             !EG(current_execute_data)->func ||
1840                             !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
1841                             EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
1842                             (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
1843                              EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
1844                                 if (zend_hash_add_empty_element(&EG(included_files), persistent_script->full_path) != NULL) {
1845                                         /* ext/phar has to load phar's metadata into memory */
1846                                         if (persistent_script->is_phar) {
1847                                                 php_stream_statbuf ssb;
1848                                                 char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->full_path));
1849 
1850                                                 memcpy(fname, "phar://", sizeof("phar://") - 1);
1851                                                 memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->full_path), ZSTR_LEN(persistent_script->full_path) + 1);
1852                                                 php_stream_stat_path(fname, &ssb);
1853                                                 efree(fname);
1854                                         }
1855                                 }
1856                         }
1857                 }
1858                 zend_file_handle_dtor(file_handle);
1859                 from_shared_memory = 1;
1860         }
1861 
1862         persistent_script->dynamic_members.last_used = ZCG(request_time);
1863 
1864         SHM_PROTECT();
1865 
1866     /* Fetch jit auto globals used in the script before execution */
1867     if (persistent_script->ping_auto_globals_mask) {
1868                 zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
1869         }
1870 
1871         return zend_accel_load_script(persistent_script, from_shared_memory);
1872 }
1873 
1874 /* zend_stream_open_function() replacement for PHP 5.3 and above */
1875 static int persistent_stream_open_function(const char *filename, zend_file_handle *handle)
1876 {
1877         if (ZCG(cache_persistent_script)) {
1878                 /* check if callback is called from include_once or it's a main request */
1879                 if ((!EG(current_execute_data) &&
1880                      filename == SG(request_info).path_translated &&
1881                      ZCG(cache_opline) == NULL) ||
1882                     (EG(current_execute_data) &&
1883                      EG(current_execute_data)->func &&
1884                      ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1885                      ZCG(cache_opline) == EG(current_execute_data)->opline)) {
1886 
1887                         /* we are in include_once or FastCGI request */
1888                         handle->filename = (char*)filename;
1889                         handle->free_filename = 0;
1890                         handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->full_path);
1891                         handle->type = ZEND_HANDLE_FILENAME;
1892                         return SUCCESS;
1893                 }
1894                 ZCG(cache_opline) = NULL;
1895                 ZCG(cache_persistent_script) = NULL;
1896         }
1897         return accelerator_orig_zend_stream_open_function(filename, handle);
1898 }
1899 
1900 /* zend_resolve_path() replacement for PHP 5.3 and above */
1901 static zend_string* persistent_zend_resolve_path(const char *filename, int filename_len)
1902 {
1903         if (ZCG(enabled) && accel_startup_ok &&
1904             (ZCG(counted) || ZCSG(accelerator_enabled)) &&
1905             !ZCSG(restart_in_progress)) {
1906 
1907                 /* check if callback is called from include_once or it's a main request */
1908                 if ((!EG(current_execute_data) &&
1909                      filename == SG(request_info).path_translated) ||
1910                     (EG(current_execute_data) &&
1911                      EG(current_execute_data)->func &&
1912                      ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1913                      EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
1914                      (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
1915                       EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
1916 
1917                         /* we are in include_once or FastCGI request */
1918                         zend_string *resolved_path;
1919                         int key_length;
1920                         char *key = NULL;
1921                         
1922                         if (!ZCG(accel_directives).revalidate_path) {
1923                                 /* lookup by "not-real" path */
1924                                 key = accel_make_persistent_key(filename, filename_len, &key_length);
1925                                 if (key) {
1926                                         zend_accel_hash_entry *bucket = zend_accel_hash_str_find_entry(&ZCSG(hash), key, key_length);
1927                                         if (bucket != NULL) {
1928                                                 zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
1929                                                 if (!persistent_script->corrupted) {
1930                                                         ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
1931                                                         ZCG(cache_persistent_script) = persistent_script;
1932                                                         return zend_string_copy(persistent_script->full_path);
1933                                                 }
1934                                         }
1935                                 } else {
1936                                         ZCG(cache_opline) = NULL;
1937                                         ZCG(cache_persistent_script) = NULL;
1938                                         return accelerator_orig_zend_resolve_path(filename, filename_len);
1939                                 }
1940                         }
1941 
1942                         /* find the full real path */
1943                         resolved_path = accelerator_orig_zend_resolve_path(filename, filename_len);
1944 
1945                         if (resolved_path) {
1946                                 /* lookup by real path */
1947                                 zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
1948                                 if (bucket) {
1949                                         zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
1950                                         if (!persistent_script->corrupted) {
1951                                                 if (key) {
1952                                                         /* add another "key" for the same bucket */
1953                                                         SHM_UNPROTECT();
1954                                                         zend_shared_alloc_lock();
1955                                                         zend_accel_add_key(key, key_length, bucket);
1956                                                         zend_shared_alloc_unlock();
1957                                                         SHM_PROTECT();
1958                                                 } else {
1959                                                         ZCG(key_len) = 0;
1960                                                 }
1961                                                 ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
1962                                                 ZCG(cache_persistent_script) = persistent_script;
1963                                                 return resolved_path;
1964                                         }
1965                                 }
1966                         }
1967 
1968                         ZCG(cache_opline) = NULL;
1969                         ZCG(cache_persistent_script) = NULL;
1970                         return resolved_path;
1971                 }
1972         }
1973         ZCG(cache_opline) = NULL;
1974         ZCG(cache_persistent_script) = NULL;
1975         return accelerator_orig_zend_resolve_path(filename, filename_len);
1976 }
1977 
1978 static void zend_reset_cache_vars(void)
1979 {
1980         ZSMMG(memory_exhausted) = 0;
1981         ZCSG(hits) = 0;
1982         ZCSG(misses) = 0;
1983         ZCSG(blacklist_misses) = 0;
1984         ZSMMG(wasted_shared_memory) = 0;
1985         ZCSG(restart_pending) = 0;
1986         ZCSG(force_restart_time) = 0;
1987 }
1988 
1989 static void accel_reset_pcre_cache(void)
1990 {
1991         Bucket *p;
1992 
1993         ZEND_HASH_FOREACH_BUCKET(&PCRE_G(pcre_cache), p) {
1994                 /* Remove PCRE cache entries with inconsistent keys */
1995                 if (zend_accel_in_shm(p->key)) {
1996                         p->key = NULL;
1997                         zend_hash_del_bucket(&PCRE_G(pcre_cache), p);
1998                 }
1999         } ZEND_HASH_FOREACH_END();
2000 }
2001 
2002 static void accel_activate(void)
2003 {
2004         zend_bool reset_pcre = 0;
2005 
2006         if (!ZCG(enabled) || !accel_startup_ok) {
2007                 return;
2008         }
2009 
2010         if (!ZCG(function_table).nTableSize) {
2011                 zend_hash_init(&ZCG(function_table), zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
2012                 zend_accel_copy_internal_functions();
2013         }
2014 
2015         /* PHP-5.4 and above return "double", but we use 1 sec precision */
2016         ZCG(auto_globals_mask) = 0;
2017         ZCG(request_time) = (time_t)sapi_get_request_time();
2018         ZCG(cache_opline) = NULL;
2019         ZCG(cache_persistent_script) = NULL;
2020         ZCG(include_path_key_len) = 0;
2021         ZCG(include_path_check) = 1;
2022 
2023         /* check if ZCG(function_table) wasn't somehow polluted on the way */
2024         if (ZCG(internal_functions_count) != zend_hash_num_elements(&ZCG(function_table))) {
2025                 zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
2026         }
2027 
2028         ZCG(cwd) = NULL;
2029         ZCG(cwd_key_len) = 0;
2030         ZCG(cwd_check) = 1;
2031 
2032 #ifdef HAVE_OPCACHE_FILE_CACHE
2033         if (ZCG(accel_directives).file_cache_only) {
2034                 return;
2035         }
2036 #endif
2037 
2038         SHM_UNPROTECT();
2039 
2040         if (ZCG(counted)) {
2041 #ifdef ZTS
2042                 zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %d", tsrm_thread_id());
2043 #else
2044                 zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
2045 #endif
2046                 accel_unlock_all();
2047                 ZCG(counted) = 0;
2048         }
2049 
2050         if (ZCSG(restart_pending)) {
2051                 zend_shared_alloc_lock();
2052                 if (ZCSG(restart_pending) != 0) { /* check again, to ensure that the cache wasn't already cleaned by another process */
2053                         if (accel_is_inactive() == SUCCESS) {
2054                                 zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
2055                                 ZCSG(restart_pending) = 0;
2056                                 switch ZCSG(restart_reason) {
2057                                         case ACCEL_RESTART_OOM:
2058                                                 ZCSG(oom_restarts)++;
2059                                                 break;
2060                                         case ACCEL_RESTART_HASH:
2061                                                 ZCSG(hash_restarts)++;
2062                                                 break;
2063                                         case ACCEL_RESTART_USER:
2064                                                 ZCSG(manual_restarts)++;
2065                                                 break;
2066                                 }
2067                                 accel_restart_enter();
2068 
2069                                 zend_reset_cache_vars();
2070                                 zend_accel_hash_clean(&ZCSG(hash));
2071 
2072 #if !defined(ZTS)
2073                                 if (ZCG(accel_directives).interned_strings_buffer) {
2074                                         accel_interned_strings_restore_state();
2075                                 }
2076 #endif
2077 
2078                                 zend_shared_alloc_restore_state();
2079                                 ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
2080                                 if (ZCSG(last_restart_time) < ZCG(request_time)) {
2081                                         ZCSG(last_restart_time) = ZCG(request_time);
2082                                 } else {
2083                                         ZCSG(last_restart_time)++;
2084                                 }
2085                                 accel_restart_leave();
2086                         }
2087                 } else {
2088                         reset_pcre = 1;
2089                 }
2090                 zend_shared_alloc_unlock();
2091         }
2092 
2093         SHM_PROTECT();
2094 
2095         if (ZCSG(last_restart_time) != ZCG(last_restart_time)) {
2096                 /* SHM was reinitialized. */
2097                 ZCG(last_restart_time) = ZCSG(last_restart_time);
2098 
2099                 /* Reset in-process realpath cache */
2100                 realpath_cache_clean();
2101 
2102                 accel_reset_pcre_cache();
2103         } else if (reset_pcre) {
2104                 accel_reset_pcre_cache();
2105         }
2106 }
2107 
2108 #if !ZEND_DEBUG
2109 
2110 /* Fast Request Shutdown
2111  * =====================
2112  * Zend Memory Manager frees memory by its own. We don't have to free each
2113  * allocated block separately, but we like to call all the destructors and
2114  * callbacks in exactly the same order.
2115  */
2116 static void accel_fast_hash_destroy(HashTable *ht);
2117 
2118 static void accel_fast_zval_dtor(zval *zvalue)
2119 {
2120 tail_call:
2121         switch (Z_TYPE_P(zvalue)) {
2122                 case IS_ARRAY:
2123                         GC_REMOVE_FROM_BUFFER(Z_ARR_P(zvalue));
2124                         if (Z_ARR_P(zvalue) != &EG(symbol_table)) {
2125                                 /* break possible cycles */
2126                                 ZVAL_NULL(zvalue);
2127                                 accel_fast_hash_destroy(Z_ARRVAL_P(zvalue));
2128                         }
2129                         break;
2130                 case IS_OBJECT:
2131                         OBJ_RELEASE(Z_OBJ_P(zvalue));
2132                         break;
2133                 case IS_RESOURCE:
2134                         zend_list_delete(Z_RES_P(zvalue));
2135                         break;
2136                 case IS_REFERENCE: {
2137                                 zend_reference *ref = Z_REF_P(zvalue);
2138 
2139                                 if (--GC_REFCOUNT(ref) == 0) {
2140                                         if (Z_REFCOUNTED(ref->val) && Z_DELREF(ref->val) == 0) {
2141                                                 zvalue = &ref->val;
2142                                                 goto tail_call;
2143                                         }
2144                                 }
2145                         }
2146                         break;
2147         }
2148 }
2149 
2150 static void accel_fast_hash_destroy(HashTable *ht)
2151 {
2152         Bucket *p = ht->arData;
2153         Bucket *end = p + ht->nNumUsed;
2154 
2155         while (p != end) {
2156                 if (Z_REFCOUNTED(p->val) && Z_DELREF(p->val) == 0) {
2157                         accel_fast_zval_dtor(&p->val);
2158                 }
2159                 p++;
2160         }
2161 }
2162 
2163 static inline void zend_accel_fast_del_bucket(HashTable *ht, uint32_t idx, Bucket *p)
2164 {
2165         uint32_t nIndex = p->h | ht->nTableMask;
2166         uint32_t i = HT_HASH(ht, nIndex);
2167 
2168         ht->nNumOfElements--;
2169         if (idx != i) {
2170                 Bucket *prev = HT_HASH_TO_BUCKET(ht, i);
2171                 while (Z_NEXT(prev->val) != idx) {
2172                         i = Z_NEXT(prev->val);
2173                         prev = HT_HASH_TO_BUCKET(ht, i);
2174                 }
2175                 Z_NEXT(prev->val) = Z_NEXT(p->val);
2176         } else {
2177                 HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
2178         }
2179 }
2180 
2181 static void zend_accel_fast_shutdown(void)
2182 {
2183         if (EG(full_tables_cleanup)) {
2184                 return;
2185         }
2186 
2187         if (EG(objects_store).top > 1 || zend_hash_num_elements(&EG(regular_list)) > 0) {
2188                 /* We don't have to destroy all zvals if they cannot call any destructors */
2189                 zend_try {
2190                         ZEND_HASH_REVERSE_FOREACH(&EG(symbol_table), 0) {
2191                                 if (Z_REFCOUNTED(_p->val) && Z_DELREF(_p->val) == 0) {
2192                                         accel_fast_zval_dtor(&_p->val);
2193                                 }
2194                                 zend_accel_fast_del_bucket(&EG(symbol_table), HT_IDX_TO_HASH(_idx-1), _p);
2195                         } ZEND_HASH_FOREACH_END();
2196                 } zend_end_try();
2197                 zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
2198 
2199                 ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
2200                         zend_function *func = Z_PTR(_p->val);
2201 
2202                         if (func->type == ZEND_INTERNAL_FUNCTION) {
2203                                 break;
2204                         } else {
2205                                 if (func->op_array.static_variables) {
2206                                         if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
2207                                                 if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
2208                                                         accel_fast_hash_destroy(func->op_array.static_variables);
2209                                                 }
2210                                         }
2211                                 }
2212                                 zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
2213                         }
2214                 } ZEND_HASH_FOREACH_END();
2215 
2216                 ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
2217                         zend_class_entry *ce = Z_PTR(_p->val);
2218 
2219                         if (ce->type == ZEND_INTERNAL_CLASS) {
2220                                 break;
2221                         } else {
2222                                 if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
2223                                         zend_function *func;
2224 
2225                                         ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
2226                                                 if (func->type == ZEND_USER_FUNCTION) {
2227                                                         if (func->op_array.static_variables) {
2228                                                                 if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
2229                                                                         if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
2230                                                                                 accel_fast_hash_destroy(func->op_array.static_variables);
2231                                                                         }
2232                                                                 }
2233                                                                 func->op_array.static_variables = NULL;
2234                                                         }
2235                                                 }
2236                                         } ZEND_HASH_FOREACH_END();
2237                                 }
2238                                 if (ce->static_members_table) {
2239                                         int i;
2240 
2241                                         for (i = 0; i < ce->default_static_members_count; i++) {
2242                                                 zval *zv = &ce->static_members_table[i];
2243                                                 ZVAL_UNDEF(&ce->static_members_table[i]);
2244                                                 if (Z_REFCOUNTED_P(zv) && Z_DELREF_P(zv) == 0) {
2245                                                         accel_fast_zval_dtor(zv);
2246                                                 }
2247                                         }
2248                                         ce->static_members_table = NULL;
2249                                 }
2250                                 zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
2251                         }
2252                 } ZEND_HASH_FOREACH_END();
2253 
2254         } else {
2255 
2256                 zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
2257 
2258                 ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
2259                         zend_function *func = Z_PTR(_p->val);
2260 
2261                         if (func->type == ZEND_INTERNAL_FUNCTION) {
2262                                 break;
2263                         } else {
2264                                 zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
2265                         }
2266                 } ZEND_HASH_FOREACH_END();
2267 
2268                 ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
2269                         zend_class_entry *ce = Z_PTR(_p->val);
2270 
2271                         if (ce->type == ZEND_INTERNAL_CLASS) {
2272                                 break;
2273                         } else {
2274                                 zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
2275                         }
2276                 } ZEND_HASH_FOREACH_END();
2277         }
2278 
2279         ZEND_HASH_REVERSE_FOREACH(EG(zend_constants), 0) {
2280                 zend_constant *c = Z_PTR(_p->val);
2281 
2282                 if (c->flags & CONST_PERSISTENT) {
2283                         break;
2284                 } else {
2285                         zend_accel_fast_del_bucket(EG(zend_constants), HT_IDX_TO_HASH(_idx-1), _p);
2286                 }
2287         } ZEND_HASH_FOREACH_END();
2288         EG(function_table)->nNumUsed = EG(function_table)->nNumOfElements;
2289         EG(class_table)->nNumUsed = EG(class_table)->nNumOfElements;
2290         EG(zend_constants)->nNumUsed = EG(zend_constants)->nNumOfElements;
2291 
2292         CG(unclean_shutdown) = 1;
2293 }
2294 #endif
2295 
2296 int accel_post_deactivate(void)
2297 {
2298         if (!ZCG(enabled) || !accel_startup_ok) {
2299                 return SUCCESS;
2300         }
2301 
2302         zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
2303         accel_unlock_all();
2304         ZCG(counted) = 0;
2305 
2306         return SUCCESS;
2307 }
2308 
2309 static void accel_deactivate(void)
2310 {
2311         /* ensure that we restore function_table and class_table
2312          * In general, they're restored by persistent_compile_file(), but in case
2313          * the script is aborted abnormally, they may become messed up.
2314          */
2315 
2316         if (ZCG(cwd)) {
2317                 zend_string_release(ZCG(cwd));
2318                 ZCG(cwd) = NULL;
2319         }
2320 
2321         if (!ZCG(enabled) || !accel_startup_ok) {
2322                 return;
2323         }
2324 
2325 #if !ZEND_DEBUG
2326         if (ZCG(accel_directives).fast_shutdown && is_zend_mm()) {
2327                 zend_accel_fast_shutdown();
2328         }
2329 #endif
2330 }
2331 
2332 static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
2333 {
2334         (void)element2; /* keep the compiler happy */
2335 
2336         if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
2337                 element1->startup = NULL;
2338 #if 0
2339                 /* We have to call shutdown callback it to free TS resources */
2340                 element1->shutdown = NULL;
2341 #endif
2342                 element1->activate = NULL;
2343                 element1->deactivate = NULL;
2344                 element1->op_array_handler = NULL;
2345 
2346 #ifdef __DEBUG_MESSAGES__
2347         fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
2348         fflush(stderr);
2349 #endif
2350         }
2351 
2352         return 0;
2353 }
2354 
2355 static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *))
2356 {
2357         accel_startup_ok = 0;
2358         zps_failure_reason = reason;
2359         zps_api_failure_reason = api_reason?api_reason:reason;
2360         zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
2361 }
2362 
2363 static inline int accel_find_sapi(void)
2364 {
2365         static const char *supported_sapis[] = {
2366                 "apache",
2367                 "fastcgi",
2368                 "cli-server",
2369                 "cgi-fcgi",
2370                 "fpm-fcgi",
2371                 "isapi",
2372                 "apache2filter",
2373                 "apache2handler",
2374                 "litespeed",
2375                 "uwsgi",
2376                 NULL
2377         };
2378         const char **sapi_name;
2379 
2380         if (sapi_module.name) {
2381                 for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
2382                         if (strcmp(sapi_module.name, *sapi_name) == 0) {
2383                                 return SUCCESS;
2384                         }
2385                 }
2386                 if (ZCG(accel_directives).enable_cli && (
2387                     strcmp(sapi_module.name, "cli") == 0
2388                   || strcmp(sapi_module.name, "phpdbg") == 0)) {
2389                         return SUCCESS;
2390                 }
2391         }
2392 
2393         return FAILURE;
2394 }
2395 
2396 static int zend_accel_init_shm(void)
2397 {
2398         zend_shared_alloc_lock();
2399 
2400         accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals));
2401         if (!accel_shared_globals) {
2402                 zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
2403                 zend_shared_alloc_unlock();
2404                 return FAILURE;
2405         }
2406         ZSMMG(app_shared_globals) = accel_shared_globals;
2407 
2408         zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
2409 
2410         ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL;
2411 # ifndef ZTS
2412         zend_hash_init(&ZCSG(interned_strings), (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024) / (sizeof(Bucket) + sizeof(Bucket*) + 8 /* average string length */), NULL, NULL, 1);
2413         if (ZCG(accel_directives).interned_strings_buffer) {
2414                 void *data;
2415 
2416                 ZCSG(interned_strings).nTableMask = -ZCSG(interned_strings).nTableSize;
2417                 data = zend_shared_alloc(HT_SIZE(&ZCSG(interned_strings)));
2418                 ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
2419                 if (!data || !ZCSG(interned_strings_start)) {
2420                         zend_accel_error(ACCEL_LOG_FATAL, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings");
2421                         zend_shared_alloc_unlock();
2422                         return FAILURE;
2423                 }
2424                 HT_SET_DATA_ADDR(&ZCSG(interned_strings), data);
2425                 HT_HASH_RESET(&ZCSG(interned_strings));
2426                 ZCSG(interned_strings_end)   = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
2427                 ZCSG(interned_strings_top)   = ZCSG(interned_strings_start);
2428 
2429 //              orig_interned_strings_start = CG(interned_strings_start);
2430 //              orig_interned_strings_end = CG(interned_strings_end);
2431 //              CG(interned_strings_start) = ZCSG(interned_strings_start);
2432 //              CG(interned_strings_end) = ZCSG(interned_strings_end);
2433         }
2434 # endif
2435 
2436         orig_new_interned_string = zend_new_interned_string;
2437         orig_interned_strings_snapshot = zend_interned_strings_snapshot;
2438         orig_interned_strings_restore = zend_interned_strings_restore;
2439         zend_new_interned_string = accel_new_interned_string_for_php;
2440         zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
2441         zend_interned_strings_restore = accel_interned_strings_restore_for_php;
2442 
2443 # ifndef ZTS
2444         if (ZCG(accel_directives).interned_strings_buffer) {
2445                 accel_use_shm_interned_strings();
2446                 accel_interned_strings_save_state();
2447         }
2448 # endif
2449 
2450         zend_reset_cache_vars();
2451 
2452         ZCSG(oom_restarts) = 0;
2453         ZCSG(hash_restarts) = 0;
2454         ZCSG(manual_restarts) = 0;
2455 
2456         ZCSG(accelerator_enabled) = 1;
2457         ZCSG(start_time) = zend_accel_get_time();
2458         ZCSG(last_restart_time) = 0;
2459         ZCSG(restart_in_progress) = 0;
2460 
2461         zend_shared_alloc_unlock();
2462 
2463         return SUCCESS;
2464 }
2465 
2466 static void accel_globals_ctor(zend_accel_globals *accel_globals)
2467 {
2468 #if defined(COMPILE_DL_OPCACHE) && defined(ZTS)
2469         ZEND_TSRMLS_CACHE_UPDATE();
2470 #endif
2471         memset(accel_globals, 0, sizeof(zend_accel_globals));
2472 }
2473 
2474 static void accel_globals_internal_func_dtor(zval *zv)
2475 {
2476         free(Z_PTR_P(zv));
2477 }
2478 
2479 static void accel_globals_dtor(zend_accel_globals *accel_globals)
2480 {
2481         if (accel_globals->function_table.nTableSize) {
2482                 accel_globals->function_table.pDestructor = accel_globals_internal_func_dtor;
2483                 zend_hash_destroy(&accel_globals->function_table);
2484         }
2485 }
2486 
2487 #define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_CHAR) ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
2488 
2489 static void accel_gen_system_id(void)
2490 {
2491         PHP_MD5_CTX context;
2492         unsigned char digest[16], c;
2493         char *md5str = ZCG(system_id);
2494         int i;
2495 
2496         PHP_MD5Init(&context);
2497         PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
2498         PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
2499         PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
2500         if (strstr(PHP_VERSION, "-dev") != 0) {
2501                 /* Development versions may be changed from build to build */
2502                 PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
2503                 PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
2504         }
2505         PHP_MD5Final(digest, &context);
2506         for (i = 0; i < 16; i++) {
2507                 c = digest[i] >> 4;
2508                 c = (c <= 9) ? c + '0' : c - 10 + 'a';
2509                 md5str[i * 2] = c;
2510                 c = digest[i] &  0x0f;
2511                 c = (c <= 9) ? c + '0' : c - 10 + 'a';
2512                 md5str[(i * 2) + 1] = c;
2513         }
2514 }
2515 
2516 #ifdef HAVE_HUGE_CODE_PAGES
2517 # ifndef _WIN32
2518 #  include <sys/mman.h>
2519 #  ifndef MAP_ANON
2520 #   ifdef MAP_ANONYMOUS
2521 #    define MAP_ANON MAP_ANONYMOUS
2522 #   endif
2523 #  endif
2524 #  ifndef MAP_FAILED
2525 #   define MAP_FAILED ((void*)-1)
2526 #  endif
2527 # endif
2528 
2529 # if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
2530 static int accel_remap_huge_pages(void *start, size_t size, const char *name, size_t offset)
2531 {
2532         void *ret = MAP_FAILED;
2533         void *mem;
2534 
2535         mem = mmap(NULL, size,
2536                 PROT_READ | PROT_WRITE,
2537                 MAP_PRIVATE | MAP_ANONYMOUS,
2538                 -1, 0);
2539         if (mem == MAP_FAILED) {
2540                 zend_error(E_WARNING,
2541                         ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap failed: %s (%d)",
2542                         strerror(errno), errno);
2543                 return -1;
2544         }
2545         memcpy(mem, start, size);
2546 
2547 #  ifdef MAP_HUGETLB
2548         ret = mmap(start, size,
2549                 PROT_READ | PROT_WRITE | PROT_EXEC,
2550                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
2551                 -1, 0);
2552 #  endif
2553         if (ret == MAP_FAILED) {
2554                 ret = mmap(start, size,
2555                         PROT_READ | PROT_WRITE | PROT_EXEC,
2556                         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
2557                         -1, 0);
2558                 /* this should never happen? */
2559                 ZEND_ASSERT(ret != MAP_FAILED);
2560 #  ifdef MADV_HUGEPAGE
2561                 if (-1 == madvise(start, size, MADV_HUGEPAGE)) {
2562                         memcpy(start, mem, size);
2563                         mprotect(start, size, PROT_READ | PROT_EXEC);
2564                         munmap(mem, size);
2565                         zend_error(E_WARNING,
2566                                 ACCELERATOR_PRODUCT_NAME " huge_code_pages: madvise(HUGEPAGE) failed: %s (%d)",
2567                                 strerror(errno), errno);
2568                         return -1;
2569                 }
2570 #  else
2571                 memcpy(start, mem, size);
2572                 mprotect(start, size, PROT_READ | PROT_EXEC);
2573                 munmap(mem, size);
2574                 zend_error(E_WARNING,
2575                         ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap(HUGETLB) failed: %s (%d)",
2576                         strerror(errno), errno);
2577                 return -1;
2578 #  endif
2579         }
2580 
2581         if (ret == start) {
2582                 memcpy(start, mem, size);
2583                 mprotect(start, size, PROT_READ | PROT_EXEC);
2584         }
2585         munmap(mem, size);
2586 
2587         return (ret == start) ? 0 : -1;
2588 }
2589 
2590 static void accel_move_code_to_huge_pages(void)
2591 {
2592         FILE *f;
2593         long unsigned int huge_page_size = 2 * 1024 * 1024;
2594 
2595         f = fopen("/proc/self/maps", "r");
2596         if (f) {
2597                 long unsigned int  start, end, offset, inode;
2598                 char perm[5], dev[6], name[MAXPATHLEN];
2599                 int ret;
2600 
2601                 ret = fscanf(f, "%lx-%lx %4s %lx %5s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name);
2602                 if (ret == 7 && perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') {
2603                         long unsigned int  seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
2604                         long unsigned int  seg_end = (end & ~(huge_page_size-1L));
2605 
2606                         if (seg_end > seg_start) {
2607                                 zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name);
2608                                 accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, name, offset + seg_start - start);
2609                         }
2610                 }
2611                 fclose(f);
2612         }
2613 }
2614 # else
2615 static void accel_move_code_to_huge_pages(void)
2616 {
2617         zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages has no affect as huge page is not supported");
2618         return;
2619 }
2620 # endif /* defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE) */
2621 #endif /* HAVE_HUGE_CODE_PAGES */
2622 
2623 static int accel_startup(zend_extension *extension)
2624 {
2625         zend_function *func;
2626         zend_ini_entry *ini_entry;
2627 
2628 #ifdef ZTS
2629         accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor);
2630 #else
2631         accel_globals_ctor(&accel_globals);
2632 #endif
2633 
2634 #ifdef ZEND_WIN32
2635         _setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
2636 #endif
2637 
2638         if (start_accel_module() == FAILURE) {
2639                 accel_startup_ok = 0;
2640                 zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
2641                 return FAILURE;
2642         }
2643 
2644         accel_gen_system_id();
2645 
2646 #ifdef HAVE_HUGE_CODE_PAGES
2647         if (ZCG(accel_directives).huge_code_pages &&
2648             (strcmp(sapi_module.name, "cli") == 0 ||
2649              strcmp(sapi_module.name, "cli-server") == 0 ||
2650                  strcmp(sapi_module.name, "cgi-fcgi") == 0 ||
2651                  strcmp(sapi_module.name, "fpm-fcgi") == 0)) {
2652                 accel_move_code_to_huge_pages();
2653         }
2654 #endif
2655 
2656         /* no supported SAPI found - disable acceleration and stop initialization */
2657         if (accel_find_sapi() == FAILURE) {
2658                 accel_startup_ok = 0;
2659                 if (!ZCG(accel_directives).enable_cli &&
2660                     strcmp(sapi_module.name, "cli") == 0) {
2661                         zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb);
2662                 } else {
2663                         zps_startup_failure("Opcode Caching is only supported in Apache, ISAPI, FPM, FastCGI and LiteSpeed SAPIs", NULL, accelerator_remove_cb);
2664                 }
2665                 return SUCCESS;
2666         }
2667 
2668         if (ZCG(enabled) == 0) {
2669                 return SUCCESS ;
2670         }
2671 
2672 /********************************************/
2673 /* End of non-SHM dependent initializations */
2674 /********************************************/
2675 #ifdef HAVE_OPCACHE_FILE_CACHE
2676         if (!ZCG(accel_directives).file_cache_only) {
2677 #else
2678         if (1) {
2679 #endif
2680                 switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
2681                         case ALLOC_SUCCESS:
2682                                 if (zend_accel_init_shm() == FAILURE) {
2683                                         accel_startup_ok = 0;
2684                                         return FAILURE;
2685                                 }
2686                                 break;
2687                         case ALLOC_FAILURE:
2688                                 accel_startup_ok = 0;
2689                                 zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
2690                                 return SUCCESS;
2691                         case SUCCESSFULLY_REATTACHED:
2692                                 zend_shared_alloc_lock();
2693                                 accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
2694                                 orig_new_interned_string = zend_new_interned_string;
2695                                 orig_interned_strings_snapshot = zend_interned_strings_snapshot;
2696                                 orig_interned_strings_restore = zend_interned_strings_restore;
2697 
2698                                 zend_new_interned_string = accel_new_interned_string_for_php;
2699                                 zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
2700                                 zend_interned_strings_restore = accel_interned_strings_restore_for_php;
2701 #ifndef ZTS
2702                                 accel_use_shm_interned_strings();
2703 #endif
2704                                 zend_shared_alloc_unlock();
2705                                 break;
2706                         case FAILED_REATTACHED:
2707                                 accel_startup_ok = 0;
2708                                 zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
2709                                 return SUCCESS;
2710                                 break;
2711 #if ENABLE_FILE_CACHE_FALLBACK
2712                         case ALLOC_FALLBACK:
2713                                 zend_shared_alloc_lock();
2714                                 fallback_process = 1;
2715                                 zend_accel_init_auto_globals();
2716                                 zend_shared_alloc_unlock();
2717                                 goto file_cache_fallback;
2718                                 break;
2719 #endif
2720                 }
2721 
2722                 /* from this point further, shared memory is supposed to be OK */
2723 
2724                 /* remeber the last restart time in the process memory */
2725                 ZCG(last_restart_time) = ZCSG(last_restart_time);
2726 
2727                 /* Init auto-global strings */
2728                 zend_accel_init_auto_globals();
2729 
2730                 zend_shared_alloc_lock();
2731                 zend_shared_alloc_save_state();
2732                 zend_shared_alloc_unlock();
2733 
2734                 SHM_PROTECT();
2735 #ifdef HAVE_OPCACHE_FILE_CACHE
2736         } else if (!ZCG(accel_directives).file_cache) {
2737                 accel_startup_ok = 0;
2738                 zend_accel_error(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
2739                 return SUCCESS;
2740         } else {
2741                 accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals));
2742 
2743                 /* Init auto-global strings */
2744                 zend_accel_init_auto_globals();
2745 #endif
2746         }
2747 #if ENABLE_FILE_CACHE_FALLBACK
2748 file_cache_fallback:
2749 #endif
2750 
2751         /* Override compiler */
2752         accelerator_orig_compile_file = zend_compile_file;
2753         zend_compile_file = persistent_compile_file;
2754 
2755         /* Override stream opener function (to eliminate open() call caused by
2756          * include/require statements ) */
2757         accelerator_orig_zend_stream_open_function = zend_stream_open_function;
2758         zend_stream_open_function = persistent_stream_open_function;
2759 
2760         /* Override path resolver function (to eliminate stat() calls caused by
2761          * include_once/require_once statements */
2762         accelerator_orig_zend_resolve_path = zend_resolve_path;
2763         zend_resolve_path = persistent_zend_resolve_path;
2764 
2765         /* Override chdir() function */
2766         if ((func = zend_hash_str_find_ptr(CG(function_table), "chdir", sizeof("chdir")-1)) != NULL &&
2767             func->type == ZEND_INTERNAL_FUNCTION) {
2768                 orig_chdir = func->internal_function.handler;
2769                 func->internal_function.handler = ZEND_FN(accel_chdir);
2770         }
2771         ZCG(cwd) = NULL;
2772         ZCG(include_path) = NULL;
2773 
2774         /* Override "include_path" modifier callback */
2775         if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
2776                 ZCG(include_path) = ini_entry->value;
2777                 orig_include_path_on_modify = ini_entry->on_modify;
2778                 ini_entry->on_modify = accel_include_path_on_modify;
2779         }
2780 
2781         accel_startup_ok = 1;
2782 
2783         /* Override file_exists(), is_file() and is_readable() */
2784         zend_accel_override_file_functions();
2785 
2786         /* Load black list */
2787         accel_blacklist.entries = NULL;
2788         if (ZCG(enabled) && accel_startup_ok &&
2789             ZCG(accel_directives).user_blacklist_filename &&
2790             *ZCG(accel_directives.user_blacklist_filename)) {
2791                 zend_accel_blacklist_init(&accel_blacklist);
2792                 zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
2793         }
2794 
2795         return SUCCESS;
2796 }
2797 
2798 static void accel_free_ts_resources()
2799 {
2800 #ifndef ZTS
2801         accel_globals_dtor(&accel_globals);
2802 #else
2803         ts_free_id(accel_globals_id);
2804 #endif
2805 }
2806 
2807 void accel_shutdown(void)
2808 {
2809         zend_ini_entry *ini_entry;
2810         zend_bool file_cache_only = 0;
2811 
2812         zend_accel_blacklist_shutdown(&accel_blacklist);
2813 
2814         if (!ZCG(enabled) || !accel_startup_ok) {
2815                 accel_free_ts_resources();
2816                 return;
2817         }
2818 
2819         if (ZCG(accel_directives).interned_strings_buffer) {
2820 #ifndef ZTS
2821                 zend_hash_clean(CG(auto_globals));
2822                 zend_hash_clean(CG(function_table));
2823                 zend_hash_clean(CG(class_table));
2824                 zend_hash_clean(EG(zend_constants));
2825 #endif
2826         }
2827 
2828         accel_reset_pcre_cache();
2829 
2830         zend_new_interned_string = orig_new_interned_string;
2831         zend_interned_strings_snapshot = orig_interned_strings_snapshot;
2832         zend_interned_strings_restore = orig_interned_strings_restore;
2833 
2834 #ifdef HAVE_OPCACHE_FILE_CACHE
2835         file_cache_only = ZCG(accel_directives).file_cache_only;
2836 #endif
2837 
2838         accel_free_ts_resources();
2839 
2840         if (!file_cache_only) {
2841                 zend_shared_alloc_shutdown();
2842         }
2843         zend_compile_file = accelerator_orig_compile_file;
2844 
2845         if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
2846                 ini_entry->on_modify = orig_include_path_on_modify;
2847         }
2848 }
2849 
2850 void zend_accel_schedule_restart(zend_accel_restart_reason reason)
2851 {
2852         if (ZCSG(restart_pending)) {
2853                 /* don't schedule twice */
2854                 return;
2855         }
2856         zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled!");
2857 
2858         SHM_UNPROTECT();
2859         ZCSG(restart_pending) = 1;
2860         ZCSG(restart_reason) = reason;
2861         ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
2862         ZCSG(accelerator_enabled) = 0;
2863 
2864         if (ZCG(accel_directives).force_restart_timeout) {
2865                 ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
2866         } else {
2867                 ZCSG(force_restart_time) = 0;
2868         }
2869         SHM_PROTECT();
2870 }
2871 
2872 /* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
2873 #ifdef ZEND_WIN32
2874 #define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub()
2875 #else
2876 #define accel_deactivate_now() accel_deactivate_sub()
2877 #endif
2878 
2879 /* ensures it is OK to read SHM
2880         if it's not OK (restart in progress) returns FAILURE
2881         if OK returns SUCCESS
2882         MUST call accelerator_shm_read_unlock after done lock operations
2883 */
2884 int accelerator_shm_read_lock(void)
2885 {
2886         if (ZCG(counted)) {
2887                 /* counted means we are holding read lock for SHM, so that nothing bad can happen */
2888                 return SUCCESS;
2889         } else {
2890                 /* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
2891                         or is in progress now */
2892                 if (accel_activate_add() == FAILURE) { /* acquire usage lock */
2893                         return FAILURE;
2894                 }
2895                 /* Now if we weren't inside restart, restart would not begin until we remove usage lock */
2896                 if (ZCSG(restart_in_progress)) {
2897                         /* we already were inside restart this means it's not safe to touch shm */
2898                         accel_deactivate_now(); /* drop usage lock */
2899                         return FAILURE;
2900                 }
2901                 ZCG(counted) = 1;
2902         }
2903         return SUCCESS;
2904 }
2905 
2906 /* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
2907 void accelerator_shm_read_unlock(void)
2908 {
2909         if (!ZCG(counted)) {
2910                 /* counted is 0 - meaning we had to readlock manually, release readlock now */
2911                 accel_deactivate_now();
2912         }
2913 }
2914 
2915 ZEND_EXT_API zend_extension zend_extension_entry = {
2916         ACCELERATOR_PRODUCT_NAME,               /* name */
2917         ACCELERATOR_VERSION,                                    /* version */
2918         "Zend Technologies",                                    /* author */
2919         "http://www.zend.com/",                                 /* URL */
2920         "Copyright (c) 1999-2016",                              /* copyright */
2921         accel_startup,                                                  /* startup */
2922         NULL,                                                                   /* shutdown */
2923         accel_activate,                                                 /* per-script activation */
2924         accel_deactivate,                                               /* per-script deactivation */
2925         NULL,                                                                   /* message handler */
2926         NULL,                                                                   /* op_array handler */
2927         NULL,                                                                   /* extended statement handler */
2928         NULL,                                                                   /* extended fcall begin handler */
2929         NULL,                                                                   /* extended fcall end handler */
2930         NULL,                                                                   /* op_array ctor */
2931         NULL,                                                                   /* op_array dtor */
2932         STANDARD_ZEND_EXTENSION_PROPERTIES
2933 };

/* [<][>][^][v][top][bottom][index][help] */