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

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