PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/opcache - ZendAccelerator.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 623 1203 51.8 %
Date: 2014-10-22 Functions: 38 60 63.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 22 Oct 2014 07:24:53 +0000 (6 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.