2013-02-13 12:26:47 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Optimizer + |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Copyright ( c ) 1998 - 2013 The PHP Group |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| This source file is subject to version 3.01 of the PHP license , |
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
| http : //www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Andi Gutmans < andi @ zend . com > |
| Zeev Suraski < zeev @ zend . com > |
| Stanislav Malyshev < stas @ zend . com > |
| Dmitry Stogov < dmitry @ zend . com > |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
# include "main/php.h"
# include "main/php_globals.h"
# include "zend.h"
# include "zend_extensions.h"
# include "zend_compile.h"
# include "ZendAccelerator.h"
# include "zend_persist.h"
# include "zend_shared_alloc.h"
# include "zend_accelerator_module.h"
# include "zend_accelerator_blacklist.h"
# include "zend_list.h"
# include "zend_execute.h"
# include "main/SAPI.h"
# include "main/php_streams.h"
# include "main/php_open_temporary_file.h"
# include "zend_API.h"
# include "zend_ini.h"
# include "TSRM/tsrm_virtual_cwd.h"
# include "zend_accelerator_util_funcs.h"
# include "zend_accelerator_hash.h"
# ifndef ZEND_WIN32
# include <netdb.h>
# endif
# ifdef ZEND_WIN32
typedef int uid_t ;
typedef int gid_t ;
# include <io.h>
# endif
# ifndef ZEND_WIN32
# include <sys / time.h>
# else
# include <process.h>
# endif
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# include <fcntl.h>
# include <signal.h>
# include <time.h>
# ifndef ZEND_WIN32
# include <sys / types.h>
# include <sys / ipc.h>
# endif
# include <sys/stat.h>
# include <errno.h>
# define MIN_FREE_MEMORY 64*1024
# define SHM_PROTECT() \
do { \
if ( ZCG ( accel_directives ) . protect_memory ) { \
zend_accel_shared_protect ( 1 TSRMLS_CC ) ; \
} \
} while ( 0 )
# define SHM_UNPROTECT() \
do { \
if ( ZCG ( accel_directives ) . protect_memory ) { \
zend_accel_shared_protect ( 0 TSRMLS_CC ) ; \
} \
} while ( 0 )
ZEND_EXTENSION ( ) ;
# ifndef ZTS
zend_accel_globals accel_globals ;
# else
int accel_globals_id ;
# endif
/* Points to the structure shared across all PHP processes */
zend_accel_shared_globals * accel_shared_globals = NULL ;
/* true globals, no need for thread safety */
2013-02-15 09:45:42 +00:00
zend_bool accel_startup_ok = 0 ;
2013-02-13 12:26:47 +00:00
static char * zps_failure_reason = NULL ;
char * zps_api_failure_reason = NULL ;
static zend_op_array * ( * accelerator_orig_compile_file ) ( zend_file_handle * file_handle , int type TSRMLS_DC ) ;
static int ( * accelerator_orig_zend_stream_open_function ) ( const char * filename , zend_file_handle * handle TSRMLS_DC ) ;
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
static char * ( * accelerator_orig_zend_resolve_path ) ( const char * filename , int filename_len TSRMLS_DC ) ;
# endif
static void ( * orig_chdir ) ( INTERNAL_FUNCTION_PARAMETERS ) = NULL ;
static ZEND_INI_MH ( ( * orig_include_path_on_modify ) ) = NULL ;
# ifdef ZEND_WIN32
# define INCREMENT(v) InterlockedIncrement(&ZCSG(v))
# define DECREMENT(v) InterlockedDecrement(&ZCSG(v))
# define LOCKVAL(v) (ZCSG(v))
# endif
# ifdef ZEND_WIN32
static time_t zend_accel_get_time ( void )
{
FILETIME now ;
GetSystemTimeAsFileTime ( & now ) ;
return ( time_t ) ( ( ( ( ( ( __int64 ) now . dwHighDateTime ) < < 32 ) | now . dwLowDateTime ) - 116444736000000000L ) / 10000000 ) ;
}
# else
# define zend_accel_get_time() time(NULL)
# endif
static inline int is_stream_path ( const char * filename )
{
const char * p ;
for ( p = filename ; isalnum ( ( int ) * p ) | | * p = = ' + ' | | * p = = ' - ' | | * p = = ' . ' ; p + + ) ;
return ( ( * p = = ' : ' ) & & ( p - filename > 1 ) & & ( p [ 1 ] = = ' / ' ) & & ( p [ 2 ] = = ' / ' ) ) ;
}
/* O+ overrides PHP chdir() function and remembers the current working directory
* in ZCG ( cwd ) and ZCG ( cwd_len ) . Later accel_getcwd ( ) can use stored value and
* avoid getcwd ( ) call .
*/
static ZEND_FUNCTION ( accel_chdir )
{
char cwd [ MAXPATHLEN ] ;
orig_chdir ( INTERNAL_FUNCTION_PARAM_PASSTHRU ) ;
2013-02-22 14:09:26 +00:00
if ( VCWD_GETCWD ( cwd , MAXPATHLEN ) ) {
if ( ZCG ( cwd ) ) {
efree ( ZCG ( cwd ) ) ;
2013-02-22 13:22:43 +00:00
}
2013-02-22 14:09:26 +00:00
ZCG ( cwd_len ) = strlen ( cwd ) ;
ZCG ( cwd ) = estrndup ( cwd , ZCG ( cwd_len ) ) ;
} else {
if ( ZCG ( cwd ) ) {
efree ( ZCG ( cwd ) ) ;
ZCG ( cwd ) = NULL ;
}
}
2013-02-13 12:26:47 +00:00
}
static inline char * accel_getcwd ( int * cwd_len TSRMLS_DC )
{
if ( ZCG ( cwd ) ) {
* cwd_len = ZCG ( cwd_len ) ;
return ZCG ( cwd ) ;
} else {
2013-02-22 14:09:26 +00:00
char cwd [ MAXPATHLEN + 1 ] ;
2013-02-13 12:26:47 +00:00
if ( ! VCWD_GETCWD ( cwd , MAXPATHLEN ) ) {
return NULL ;
}
2013-02-22 14:09:26 +00:00
* cwd_len = ZCG ( cwd_len ) = strlen ( cwd ) ;
2013-02-13 12:26:47 +00:00
ZCG ( cwd ) = estrndup ( cwd , ZCG ( cwd_len ) ) ;
return ZCG ( cwd ) ;
}
}
/* O+ traks changes of "include_path" directive. It stores all the requested
* values in ZCG ( include_paths ) shared hash table , current value in
* ZCG ( include_path ) / ZCG ( include_path_len ) and one letter " path key " in
* ZCG ( include_path_key ) .
*/
static ZEND_INI_MH ( accel_include_path_on_modify )
{
int ret = orig_include_path_on_modify ( entry , new_value , new_value_length , mh_arg1 , mh_arg2 , mh_arg3 , stage TSRMLS_CC ) ;
ZCG ( include_path_key ) = NULL ;
if ( ret = = SUCCESS ) {
ZCG ( include_path ) = new_value ;
if ( ZCG ( include_path ) & & * ZCG ( include_path ) ) {
ZCG ( include_path_len ) = new_value_length ;
2013-02-25 06:35:59 +00:00
if ( ZCG ( enabled ) & & accel_startup_ok & &
2013-02-13 12:26:47 +00:00
( ZCG ( counted ) | | ZCSG ( accelerator_enabled ) ) & &
! zend_accel_hash_is_full ( & ZCSG ( include_paths ) ) ) {
SHM_UNPROTECT ( ) ;
zend_shared_alloc_lock ( TSRMLS_C ) ;
ZCG ( include_path_key ) = zend_accel_hash_find ( & ZCSG ( include_paths ) , ZCG ( include_path ) , ZCG ( include_path_len ) + 1 ) ;
if ( ! ZCG ( include_path_key ) & &
! zend_accel_hash_is_full ( & ZCSG ( include_paths ) ) ) {
char * key ;
key = zend_shared_alloc ( ZCG ( include_path_len ) + 2 ) ;
if ( key ) {
memcpy ( key , ZCG ( include_path ) , ZCG ( include_path_len ) + 1 ) ;
key [ ZCG ( include_path_len ) + 1 ] = ' A ' + ZCSG ( include_paths ) . num_entries ;
ZCG ( include_path_key ) = key + ZCG ( include_path_len ) + 1 ;
zend_accel_hash_update ( & ZCSG ( include_paths ) , key , ZCG ( include_path_len ) + 1 , 0 , ZCG ( include_path_key ) ) ;
}
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
SHM_PROTECT ( ) ;
} else {
ZCG ( include_path_check ) = 1 ;
}
} else {
ZCG ( include_path ) = " " ;
ZCG ( include_path_len ) = 0 ;
}
}
return ret ;
}
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
/* Interned strings support */
static char * orig_interned_strings_start ;
static char * orig_interned_strings_end ;
static const char * ( * orig_new_interned_string ) ( const char * str , int len , int free_src TSRMLS_DC ) ;
static void ( * orig_interned_strings_snapshot ) ( TSRMLS_D ) ;
static void ( * orig_interned_strings_restore ) ( TSRMLS_D ) ;
/* O+ disables creation of interned strings by regular PHP compiler, instead,
* it creates interned strings in shared memory when saves a script .
2013-02-15 05:48:37 +00:00
* Such interned strings are shared across all PHP processes
2013-02-13 12:26:47 +00:00
*/
static const char * accel_new_interned_string_for_php ( const char * str , int len , int free_src TSRMLS_DC )
{
return str ;
}
static void accel_interned_strings_snapshot_for_php ( TSRMLS_D )
{
}
static void accel_interned_strings_restore_for_php ( TSRMLS_D )
{
}
# ifndef ZTS
static void accel_interned_strings_restore_state ( TSRMLS_D )
{
unsigned int i ;
for ( i = 0 ; i < ZCSG ( interned_strings ) . nTableSize ; i + + ) {
ZCSG ( interned_strings ) . arBuckets [ i ] = ZCSG ( interned_strings_saved_state ) . arBuckets [ i ] ;
if ( ZCSG ( interned_strings ) . arBuckets [ i ] ) {
ZCSG ( interned_strings ) . arBuckets [ i ] - > pLast = NULL ;
}
}
ZCSG ( interned_strings ) . pListHead = ZCSG ( interned_strings_saved_state ) . pListHead ;
ZCSG ( interned_strings ) . pListTail = ZCSG ( interned_strings_saved_state ) . pListTail ;
if ( ZCSG ( interned_strings ) . pListHead ) {
ZCSG ( interned_strings ) . pListHead - > pListLast = NULL ;
}
if ( ZCSG ( interned_strings ) . pListTail ) {
ZCSG ( interned_strings ) . pListTail - > pListNext = NULL ;
}
ZCSG ( interned_strings_top ) = ZCSG ( interned_strings_saved_state ) . top ;
}
static void accel_interned_strings_save_state ( TSRMLS_D )
{
ZCSG ( interned_strings_saved_state ) . arBuckets = ( Bucket * * ) zend_shared_alloc ( ZCSG ( interned_strings ) . nTableSize * sizeof ( Bucket * ) ) ;
if ( ! ZCSG ( interned_strings_saved_state ) . arBuckets ) {
zend_accel_error ( ACCEL_LOG_FATAL , " Insufficient shared memory! " ) ;
}
memcpy ( ZCSG ( interned_strings_saved_state ) . arBuckets , ZCSG ( interned_strings ) . arBuckets , ZCSG ( interned_strings ) . nTableSize * sizeof ( Bucket * ) ) ;
ZCSG ( interned_strings_saved_state ) . pListHead = ZCSG ( interned_strings ) . pListHead ;
ZCSG ( interned_strings_saved_state ) . pListTail = ZCSG ( interned_strings ) . pListTail ;
ZCSG ( interned_strings_saved_state ) . top = ZCSG ( interned_strings_top ) ;
}
# endif
const char * accel_new_interned_string ( const char * arKey , int nKeyLength , int free_src TSRMLS_DC )
{
/* for now interned strings are supported only for non-ZTS build */
# ifndef ZTS
ulong h ;
uint nIndex ;
Bucket * p ;
if ( arKey > = ZCSG ( interned_strings_start ) & & arKey < ZCSG ( interned_strings_end ) ) {
/* this is already an interned string */
return arKey ;
}
h = zend_inline_hash_func ( arKey , nKeyLength ) ;
nIndex = h & ZCSG ( interned_strings ) . nTableMask ;
/* check for existing interned string */
p = ZCSG ( interned_strings ) . arBuckets [ nIndex ] ;
while ( p ! = NULL ) {
if ( ( p - > h = = h ) & & ( p - > nKeyLength = = ( uint ) nKeyLength ) ) {
if ( ! memcmp ( p - > arKey , arKey , nKeyLength ) ) {
if ( free_src ) {
efree ( ( char * ) arKey ) ;
}
return p - > arKey ;
}
}
p = p - > pNext ;
}
if ( ZCSG ( interned_strings_top ) + ZEND_MM_ALIGNED_SIZE ( sizeof ( Bucket ) + nKeyLength ) > =
ZCSG ( interned_strings_end ) ) {
/* no memory, return the same non-interned string */
return arKey ;
}
/* create new interning string in shared interned strings buffer */
p = ( Bucket * ) ZCSG ( interned_strings_top ) ;
ZCSG ( interned_strings_top ) + = ZEND_MM_ALIGNED_SIZE ( sizeof ( Bucket ) + nKeyLength ) ;
2013-02-22 06:56:05 +00:00
p - > arKey = ( char * ) ( p + 1 ) ;
2013-02-13 12:26:47 +00:00
memcpy ( ( char * ) p - > arKey , arKey , nKeyLength ) ;
p - > nKeyLength = nKeyLength ;
p - > h = h ;
p - > pData = & p - > pDataPtr ;
p - > pDataPtr = p ;
p - > pNext = ZCSG ( interned_strings ) . arBuckets [ nIndex ] ;
p - > pLast = NULL ;
if ( p - > pNext ) {
p - > pNext - > pLast = p ;
}
ZCSG ( interned_strings ) . arBuckets [ nIndex ] = p ;
p - > pListLast = ZCSG ( interned_strings ) . pListTail ;
ZCSG ( interned_strings ) . pListTail = p ;
p - > pListNext = NULL ;
if ( p - > pListLast ! = NULL ) {
p - > pListLast - > pListNext = p ;
}
if ( ! ZCSG ( interned_strings ) . pListHead ) {
ZCSG ( interned_strings ) . pListHead = p ;
}
ZCSG ( interned_strings ) . nNumOfElements + + ;
if ( free_src ) {
efree ( ( char * ) arKey ) ;
}
return p - > arKey ;
# else
return arKey ;
# endif
}
# ifndef ZTS
/* Copy PHP interned strings from PHP process memory into the shared memory */
static void accel_use_shm_interned_strings ( TSRMLS_D )
{
Bucket * p , * q ;
/* function table hash keys */
p = CG ( function_table ) - > pListHead ;
while ( p ) {
if ( p - > nKeyLength ) {
p - > arKey = accel_new_interned_string ( p - > arKey , p - > nKeyLength , 0 TSRMLS_CC ) ;
}
p = p - > pListNext ;
}
/* class table hash keys, class names, properties, methods, constants, etc */
p = CG ( class_table ) - > pListHead ;
while ( p ) {
zend_class_entry * ce = ( zend_class_entry * ) ( p - > pDataPtr ) ;
if ( p - > nKeyLength ) {
p - > arKey = accel_new_interned_string ( p - > arKey , p - > nKeyLength , 0 TSRMLS_CC ) ;
}
if ( ce - > name ) {
2013-02-22 06:56:05 +00:00
ce - > name = accel_new_interned_string ( ce - > name , ce - > name_length + 1 , 0 TSRMLS_CC ) ;
2013-02-13 12:26:47 +00:00
}
q = ce - > properties_info . pListHead ;
while ( q ) {
zend_property_info * info = ( zend_property_info * ) ( q - > pData ) ;
if ( q - > nKeyLength ) {
q - > arKey = accel_new_interned_string ( q - > arKey , q - > nKeyLength , 0 TSRMLS_CC ) ;
}
if ( info - > name ) {
2013-02-22 06:56:05 +00:00
info - > name = accel_new_interned_string ( info - > name , info - > name_length + 1 , 0 TSRMLS_CC ) ;
2013-02-13 12:26:47 +00:00
}
q = q - > pListNext ;
}
q = ce - > function_table . pListHead ;
while ( q ) {
if ( q - > nKeyLength ) {
q - > arKey = accel_new_interned_string ( q - > arKey , q - > nKeyLength , 0 TSRMLS_CC ) ;
}
q = q - > pListNext ;
}
q = ce - > constants_table . pListHead ;
while ( q ) {
if ( q - > nKeyLength ) {
q - > arKey = accel_new_interned_string ( q - > arKey , q - > nKeyLength , 0 TSRMLS_CC ) ;
}
q = q - > pListNext ;
}
p = p - > pListNext ;
}
/* constant hash keys */
p = EG ( zend_constants ) - > pListHead ;
while ( p ) {
if ( p - > nKeyLength ) {
p - > arKey = accel_new_interned_string ( p - > arKey , p - > nKeyLength , 0 TSRMLS_CC ) ;
}
p = p - > pListNext ;
}
/* auto globals hash keys and names */
p = CG ( auto_globals ) - > pListHead ;
while ( p ) {
zend_auto_global * auto_global = ( zend_auto_global * ) p - > pData ;
auto_global - > name = accel_new_interned_string ( auto_global - > name , auto_global - > name_len + 1 , 0 TSRMLS_CC ) ;
if ( p - > nKeyLength ) {
p - > arKey = accel_new_interned_string ( p - > arKey , p - > nKeyLength , 0 TSRMLS_CC ) ;
}
p = p - > pListNext ;
}
}
# endif
# endif
static inline void accel_restart_enter ( TSRMLS_D )
{
# ifdef ZEND_WIN32
INCREMENT ( restart_in ) ;
# else
static const FLOCK_STRUCTURE ( restart_in_progress , F_WRLCK , SEEK_SET , 2 , 1 ) ;
2013-02-22 06:56:05 +00:00
if ( fcntl ( lock_file , F_SETLK , & restart_in_progress ) = = - 1 ) {
2013-02-13 12:26:47 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " RestartC(+1): %s (%d) " , strerror ( errno ) , errno ) ;
}
# endif
ZCSG ( restart_in_progress ) = 1 ;
}
static inline void accel_restart_leave ( TSRMLS_D )
{
# ifdef ZEND_WIN32
2013-02-18 08:33:58 +00:00
ZCSG ( restart_in_progress ) = 0 ;
2013-02-13 12:26:47 +00:00
DECREMENT ( restart_in ) ;
# else
static const FLOCK_STRUCTURE ( restart_finished , F_UNLCK , SEEK_SET , 2 , 1 ) ;
2013-02-18 08:33:58 +00:00
ZCSG ( restart_in_progress ) = 0 ;
2013-02-22 06:56:05 +00:00
if ( fcntl ( lock_file , F_SETLK , & restart_finished ) = = - 1 ) {
2013-02-13 12:26:47 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " RestartC(-1): %s (%d) " , strerror ( errno ) , errno ) ;
}
# endif
}
static inline int accel_restart_is_active ( TSRMLS_D )
{
2013-02-22 06:56:05 +00:00
if ( ZCSG ( restart_in_progress ) ) {
2013-02-13 12:26:47 +00:00
# ifndef ZEND_WIN32
FLOCK_STRUCTURE ( restart_check , F_WRLCK , SEEK_SET , 2 , 1 ) ;
if ( fcntl ( lock_file , F_GETLK , & restart_check ) = = - 1 ) {
zend_accel_error ( ACCEL_LOG_DEBUG , " RestartC: %s (%d) " , strerror ( errno ) , errno ) ;
return FAILURE ;
}
if ( restart_check . l_type = = F_UNLCK ) {
ZCSG ( restart_in_progress ) = 0 ;
return 0 ;
} else {
return 1 ;
}
# else
return LOCKVAL ( restart_in ) ! = 0 ;
# endif
}
return 0 ;
}
/* Creates a read lock for SHM access */
static inline void accel_activate_add ( TSRMLS_D )
{
# ifdef ZEND_WIN32
INCREMENT ( mem_usage ) ;
# else
static const FLOCK_STRUCTURE ( mem_usage_lock , F_RDLCK , SEEK_SET , 1 , 1 ) ;
2013-02-22 06:56:05 +00:00
if ( fcntl ( lock_file , F_SETLK , & mem_usage_lock ) = = - 1 ) {
2013-02-13 12:26:47 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " UpdateC(+1): %s (%d) " , strerror ( errno ) , errno ) ;
}
# endif
}
/* Releases a lock for SHM access */
static inline void accel_deactivate_sub ( TSRMLS_D )
{
# ifdef ZEND_WIN32
if ( ZCG ( counted ) ) {
DECREMENT ( mem_usage ) ;
ZCG ( counted ) = 0 ;
}
# else
static const FLOCK_STRUCTURE ( mem_usage_unlock , F_UNLCK , SEEK_SET , 1 , 1 ) ;
2013-02-22 06:56:05 +00:00
if ( fcntl ( lock_file , F_SETLK , & mem_usage_unlock ) = = - 1 ) {
2013-02-13 12:26:47 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " UpdateC(-1): %s (%d) " , strerror ( errno ) , errno ) ;
}
# endif
}
static inline void accel_unlock_all ( TSRMLS_D )
{
# ifdef ZEND_WIN32
accel_deactivate_sub ( TSRMLS_C ) ;
# else
static const FLOCK_STRUCTURE ( mem_usage_unlock_all , F_UNLCK , SEEK_SET , 0 , 0 ) ;
2013-02-22 06:56:05 +00:00
if ( fcntl ( lock_file , F_SETLK , & mem_usage_unlock_all ) = = - 1 ) {
2013-02-13 12:26:47 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " UnlockAll: %s (%d) " , strerror ( errno ) , errno ) ;
}
# endif
}
# ifndef ZEND_WIN32
static inline void kill_all_lockers ( struct flock * mem_usage_check )
{
int tries = 10 ;
/* so that other process won't try to force while we are busy cleaning up */
ZCSG ( force_restart_time ) = 0 ;
while ( mem_usage_check - > l_pid > 0 ) {
while ( tries - - ) {
zend_accel_error ( ACCEL_LOG_INFO , " Killed locker %d " , mem_usage_check - > l_pid ) ;
if ( kill ( mem_usage_check - > l_pid , SIGKILL ) ) {
break ;
}
/* give it a chance to die */
usleep ( 20000 ) ;
if ( kill ( mem_usage_check - > l_pid , 0 ) ) {
/* can't kill it */
break ;
}
usleep ( 10000 ) ;
}
if ( ! tries ) {
zend_accel_error ( ACCEL_LOG_INFO , " Can't kill %d after 20 tries! " , mem_usage_check - > l_pid ) ;
ZCSG ( force_restart_time ) = time ( NULL ) ; /* restore forced restart request */
}
mem_usage_check - > l_type = F_WRLCK ;
mem_usage_check - > l_whence = SEEK_SET ;
mem_usage_check - > l_start = 1 ;
mem_usage_check - > l_len = 1 ;
mem_usage_check - > l_pid = - 1 ;
if ( fcntl ( lock_file , F_GETLK , mem_usage_check ) = = - 1 ) {
zend_accel_error ( ACCEL_LOG_DEBUG , " KLockers: %s (%d) " , strerror ( errno ) , errno ) ;
break ;
}
if ( mem_usage_check - > l_type = = F_UNLCK | | mem_usage_check - > l_pid < = 0 ) {
break ;
}
}
}
# endif
static inline int accel_is_inactive ( TSRMLS_D )
{
# ifdef ZEND_WIN32
if ( LOCKVAL ( mem_usage ) = = 0 ) {
return SUCCESS ;
}
# else
FLOCK_STRUCTURE ( mem_usage_check , F_WRLCK , SEEK_SET , 1 , 1 ) ;
mem_usage_check . l_pid = - 1 ;
if ( fcntl ( lock_file , F_GETLK , & mem_usage_check ) = = - 1 ) {
zend_accel_error ( ACCEL_LOG_DEBUG , " UpdateC: %s (%d) " , strerror ( errno ) , errno ) ;
return FAILURE ;
}
if ( mem_usage_check . l_type = = F_UNLCK ) {
return SUCCESS ;
}
if ( ZCG ( accel_directives ) . force_restart_timeout
& & ZCSG ( force_restart_time )
2013-02-22 06:56:05 +00:00
& & time ( NULL ) > = ZCSG ( force_restart_time ) ) {
2013-02-13 12:26:47 +00:00
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 ) ;
kill_all_lockers ( & mem_usage_check ) ;
return FAILURE ; /* next request should be able to restart it */
}
# endif
return FAILURE ;
}
static int zend_get_stream_timestamp ( const char * filename , struct stat * statbuf TSRMLS_DC )
{
php_stream_wrapper * wrapper ;
php_stream_statbuf stream_statbuf ;
2013-02-20 14:04:07 +00:00
int ret , er ;
2013-02-13 12:26:47 +00:00
2013-02-22 06:56:05 +00:00
if ( ! filename ) {
2013-02-13 12:26:47 +00:00
return FAILURE ;
}
wrapper = php_stream_locate_url_wrapper ( filename , NULL , STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC ) ;
2013-02-22 06:56:05 +00:00
if ( ! wrapper ) {
2013-02-13 12:26:47 +00:00
return FAILURE ;
}
2013-02-22 06:56:05 +00:00
if ( ! wrapper - > wops | | ! wrapper - > wops - > url_stat ) {
2013-02-13 12:26:47 +00:00
statbuf - > st_mtime = 1 ;
return SUCCESS ; /* anything other than 0 is considered to be a valid timestamp */
}
2013-02-20 14:04:07 +00:00
er = EG ( error_reporting ) ;
EG ( error_reporting ) = 0 ;
zend_try {
ret = wrapper - > wops - > url_stat ( wrapper , ( char * ) filename , PHP_STREAM_URL_STAT_QUIET , & stream_statbuf , NULL TSRMLS_CC ) ;
} zend_catch {
ret = - 1 ;
} zend_end_try ( ) ;
EG ( error_reporting ) = er ;
if ( ret ! = 0 ) {
2013-02-13 12:26:47 +00:00
return FAILURE ;
}
2013-02-20 14:04:07 +00:00
2013-02-13 12:26:47 +00:00
* statbuf = stream_statbuf . sb ;
return SUCCESS ;
}
# if ZEND_WIN32
static accel_time_t zend_get_file_handle_timestamp_win ( zend_file_handle * file_handle )
{
static unsigned __int64 utc_base = 0 ;
static FILETIME utc_base_ft ;
WIN32_FILE_ATTRIBUTE_DATA fdata ;
2013-02-22 06:56:05 +00:00
if ( ! file_handle - > opened_path ) {
2013-02-13 12:26:47 +00:00
return 0 ;
}
if ( ! utc_base ) {
SYSTEMTIME st ;
st . wYear = 1970 ;
st . wMonth = 1 ;
st . wDay = 1 ;
st . wHour = 0 ;
st . wMinute = 0 ;
st . wSecond = 0 ;
st . wMilliseconds = 0 ;
SystemTimeToFileTime ( & st , & utc_base_ft ) ;
utc_base = ( ( ( unsigned __int64 ) utc_base_ft . dwHighDateTime ) < < 32 ) + utc_base_ft . dwLowDateTime ;
}
2013-02-22 06:56:05 +00:00
if ( GetFileAttributesEx ( file_handle - > opened_path , GetFileExInfoStandard , & fdata ) ! = 0 ) {
2013-02-13 12:26:47 +00:00
unsigned __int64 ftime ;
2013-02-25 07:29:54 +00:00
if ( CompareFileTime ( & fdata . ftLastWriteTime , & utc_base_ft ) < 0 ) {
2013-02-13 12:26:47 +00:00
return 0 ;
2013-02-25 07:29:54 +00:00
}
2013-02-13 12:26:47 +00:00
ftime = ( ( ( unsigned __int64 ) fdata . ftLastWriteTime . dwHighDateTime ) < < 32 ) + fdata . ftLastWriteTime . dwLowDateTime - utc_base ;
ftime / = 10000000L ;
return ( accel_time_t ) ftime ;
}
return 0 ;
}
# endif
static accel_time_t zend_get_file_handle_timestamp ( zend_file_handle * file_handle TSRMLS_DC )
{
struct stat statbuf ;
2013-03-05 19:24:58 +00:00
# ifdef ZEND_WIN32
accel_time_t res ;
# endif
2013-02-13 12:26:47 +00:00
2013-03-05 08:17:18 +00:00
if ( sapi_module . get_stat & &
! EG ( opline_ptr ) & &
file_handle - > filename = = SG ( request_info ) . path_translated ) {
struct stat * tmpbuf = sapi_module . get_stat ( TSRMLS_C ) ;
if ( tmpbuf ) {
return tmpbuf - > st_mtime ;
}
}
2013-02-13 12:26:47 +00:00
# ifdef ZEND_WIN32
res = zend_get_file_handle_timestamp_win ( file_handle ) ;
2013-02-22 06:56:05 +00:00
if ( res ) {
2013-02-13 12:26:47 +00:00
return res ;
}
# endif
switch ( file_handle - > type ) {
case ZEND_HANDLE_FD :
2013-02-22 06:56:05 +00:00
if ( fstat ( file_handle - > handle . fd , & statbuf ) = = - 1 ) {
2013-02-13 12:26:47 +00:00
return 0 ;
}
break ;
case ZEND_HANDLE_FP :
if ( fstat ( fileno ( file_handle - > handle . fp ) , & statbuf ) = = - 1 ) {
if ( zend_get_stream_timestamp ( file_handle - > filename , & statbuf TSRMLS_CC ) ! = SUCCESS ) {
return 0 ;
}
}
break ;
case ZEND_HANDLE_FILENAME :
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
case ZEND_HANDLE_MAPPED :
# endif
{
char * file_path = file_handle - > opened_path ;
2013-02-22 06:56:05 +00:00
if ( file_path ) {
2013-02-13 12:26:47 +00:00
if ( is_stream_path ( file_path ) ) {
if ( zend_get_stream_timestamp ( file_path , & statbuf TSRMLS_CC ) = = SUCCESS ) {
break ;
}
}
2013-02-22 06:56:05 +00:00
if ( VCWD_STAT ( file_path , & statbuf ) ! = - 1 ) {
2013-02-13 12:26:47 +00:00
break ;
}
}
if ( zend_get_stream_timestamp ( file_handle - > filename , & statbuf TSRMLS_CC ) ! = SUCCESS ) {
return 0 ;
}
break ;
}
case ZEND_HANDLE_STREAM :
{
php_stream * stream = ( php_stream * ) file_handle - > handle . stream . handle ;
php_stream_statbuf sb ;
2013-02-20 14:04:07 +00:00
int ret , er ;
2013-02-13 12:26:47 +00:00
if ( ! stream | |
! stream - > ops | |
2013-02-20 14:04:07 +00:00
! stream - > ops - > stat ) {
2013-02-13 12:26:47 +00:00
return 0 ;
}
2013-02-20 14:04:07 +00:00
er = EG ( error_reporting ) ;
EG ( error_reporting ) = 0 ;
zend_try {
ret = stream - > ops - > stat ( stream , & sb TSRMLS_CC ) ;
} zend_catch {
ret = - 1 ;
} zend_end_try ( ) ;
2013-02-13 12:26:47 +00:00
EG ( error_reporting ) = er ;
2013-02-20 14:04:07 +00:00
if ( ret ! = 0 ) {
return 0 ;
}
2013-02-13 12:26:47 +00:00
statbuf = sb . sb ;
}
break ;
default :
return 0 ;
}
return statbuf . st_mtime ;
}
static inline int do_validate_timestamps ( zend_persistent_script * persistent_script , zend_file_handle * file_handle TSRMLS_DC )
{
zend_file_handle ps_handle ;
2013-03-05 08:17:18 +00:00
char actualpath [ MAXPATHLEN + 1 ] ;
char * full_path_ptr = NULL ;
2013-02-13 12:26:47 +00:00
/** check that the persistant script is indeed the same file we cached
* ( if part of the path is a symlink than it possible that the user will change it )
* See bug # 15140
*/
if ( file_handle - > opened_path ) {
2013-02-22 06:56:05 +00:00
if ( strcmp ( persistent_script - > full_path , file_handle - > opened_path ) ! = 0 ) {
2013-02-13 12:26:47 +00:00
return FAILURE ;
}
} else {
full_path_ptr = VCWD_REALPATH ( file_handle - > filename , actualpath ) ;
2013-02-22 06:56:05 +00:00
if ( full_path_ptr & & strcmp ( persistent_script - > full_path , full_path_ptr ) ! = 0 ) {
2013-02-13 12:26:47 +00:00
return FAILURE ;
}
2013-03-05 08:17:18 +00:00
file_handle - > opened_path = full_path_ptr ;
2013-02-13 12:26:47 +00:00
}
if ( persistent_script - > timestamp = = 0 ) {
2013-03-05 08:17:18 +00:00
if ( full_path_ptr ) {
file_handle - > opened_path = NULL ;
}
2013-02-13 12:26:47 +00:00
return FAILURE ;
}
if ( zend_get_file_handle_timestamp ( file_handle TSRMLS_CC ) = = persistent_script - > timestamp ) {
2013-03-05 08:17:18 +00:00
if ( full_path_ptr ) {
file_handle - > opened_path = NULL ;
}
2013-02-13 12:26:47 +00:00
return SUCCESS ;
}
2013-03-05 08:17:18 +00:00
if ( full_path_ptr ) {
file_handle - > opened_path = NULL ;
}
2013-02-13 12:26:47 +00:00
ps_handle . type = ZEND_HANDLE_FILENAME ;
ps_handle . filename = persistent_script - > full_path ;
ps_handle . opened_path = persistent_script - > full_path ;
if ( zend_get_file_handle_timestamp ( & ps_handle TSRMLS_CC ) = = persistent_script - > timestamp ) {
return SUCCESS ;
}
return FAILURE ;
}
static void zend_accel_schedule_restart_if_necessary ( TSRMLS_D )
{
if ( ( ( ( double ) ZSMMG ( wasted_shared_memory ) ) / ZCG ( accel_directives ) . memory_consumption ) > = ZCG ( accel_directives ) . max_wasted_percentage ) {
zend_accel_schedule_restart ( TSRMLS_C ) ;
}
}
static inline int validate_timestamp_and_record ( zend_persistent_script * persistent_script , zend_file_handle * file_handle TSRMLS_DC )
{
2013-02-21 08:11:03 +00:00
if ( ZCG ( accel_directives ) . revalidate_freq & &
( persistent_script - > dynamic_members . revalidate > = ZCSG ( revalidate_at ) ) ) {
2013-02-13 12:26:47 +00:00
return SUCCESS ;
2013-02-22 06:56:05 +00:00
} else if ( do_validate_timestamps ( persistent_script , file_handle TSRMLS_CC ) = = FAILURE ) {
2013-02-13 12:26:47 +00:00
return FAILURE ;
} else {
persistent_script - > dynamic_members . revalidate = ZCSG ( revalidate_at ) ;
return SUCCESS ;
}
}
static unsigned int zend_accel_script_checksum ( zend_persistent_script * persistent_script )
{
signed char * mem = ( signed char * ) persistent_script - > mem ;
size_t size = persistent_script - > size ;
size_t persistent_script_check_block_size = ( ( char * ) & ( persistent_script - > dynamic_members ) ) - ( char * ) persistent_script ;
unsigned int checksum = ADLER32_INIT ;
if ( mem < ( signed char * ) persistent_script ) {
checksum = zend_adler32 ( checksum , mem , ( signed char * ) persistent_script - mem ) ;
size - = ( signed char * ) persistent_script - mem ;
mem + = ( signed char * ) persistent_script - mem ;
}
zend_adler32 ( checksum , mem , persistent_script_check_block_size ) ;
mem + = sizeof ( * persistent_script ) ;
size - = sizeof ( * persistent_script ) ;
if ( size > 0 ) {
checksum = zend_adler32 ( checksum , mem , size ) ;
}
return checksum ;
}
/* Instead of resolving full real path name each time we need to identify file,
* we create a key that consist from requested file name , current working
* directory , current include_path , etc */
char * accel_make_persistent_key_ex ( zend_file_handle * file_handle , int path_length , int * key_len TSRMLS_DC )
{
int key_length ;
/* CWD and include_path don't matter for absolute file names and streams */
if ( ZCG ( accel_directives ) . use_cwd & &
! IS_ABSOLUTE_PATH ( file_handle - > filename , path_length ) & &
! is_stream_path ( file_handle - > filename ) ) {
2013-02-22 06:56:05 +00:00
char * include_path = NULL ;
int include_path_len = 0 ;
2013-02-13 12:26:47 +00:00
const char * parent_script = NULL ;
2013-02-22 06:56:05 +00:00
int parent_script_len = 0 ;
int cur_len = 0 ;
2013-02-13 12:26:47 +00:00
int cwd_len ;
char * cwd ;
if ( ( cwd = accel_getcwd ( & cwd_len TSRMLS_CC ) ) = = NULL ) {
/* we don't handle this well for now. */
zend_accel_error ( ACCEL_LOG_INFO , " getcwd() failed for '%s' (%d), please try to set zend_optimizerplus.use_cwd to 0 in ini file " , file_handle - > filename , errno ) ;
2013-02-22 06:56:05 +00:00
if ( file_handle - > opened_path ) {
2013-02-13 12:26:47 +00:00
cwd = file_handle - > opened_path ;
cwd_len = strlen ( cwd ) ;
} else {
ZCG ( key_len ) = 0 ;
return NULL ;
}
}
if ( ZCG ( include_path_key ) ) {
include_path = ZCG ( include_path_key ) ;
include_path_len = 1 ;
} else {
include_path = ZCG ( include_path ) ;
include_path_len = ZCG ( include_path_len ) ;
if ( ZCG ( include_path_check ) & &
2013-02-25 06:35:59 +00:00
ZCG ( enabled ) & & accel_startup_ok & &
2013-02-13 12:26:47 +00:00
( ZCG ( counted ) | | ZCSG ( accelerator_enabled ) ) & &
! zend_accel_hash_is_full ( & ZCSG ( include_paths ) ) ) {
SHM_UNPROTECT ( ) ;
zend_shared_alloc_lock ( TSRMLS_C ) ;
ZCG ( include_path_key ) = zend_accel_hash_find ( & ZCSG ( include_paths ) , ZCG ( include_path ) , ZCG ( include_path_len ) + 1 ) ;
if ( ZCG ( include_path_key ) ) {
include_path = ZCG ( include_path_key ) ;
include_path_len = 1 ;
} else if ( ! zend_accel_hash_is_full ( & ZCSG ( include_paths ) ) ) {
char * key ;
key = zend_shared_alloc ( ZCG ( include_path_len ) + 2 ) ;
if ( key ) {
memcpy ( key , ZCG ( include_path ) , ZCG ( include_path_len ) + 1 ) ;
key [ ZCG ( include_path_len ) + 1 ] = ' A ' + ZCSG ( include_paths ) . num_entries ;
ZCG ( include_path_key ) = key + ZCG ( include_path_len ) + 1 ;
zend_accel_hash_update ( & ZCSG ( include_paths ) , key , ZCG ( include_path_len ) + 1 , 0 , ZCG ( include_path_key ) ) ;
include_path = ZCG ( include_path_key ) ;
include_path_len = 1 ;
}
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
SHM_PROTECT ( ) ;
}
}
/* Here we add to the key the parent script directory,
since fopen_wrappers from version 4.0 .7 use current script ' s path
in include path too .
*/
if ( EG ( in_execution ) & &
( parent_script = zend_get_executed_filename ( TSRMLS_C ) ) ! = NULL & &
parent_script [ 0 ] ! = ' [ ' ) {
parent_script_len = strlen ( parent_script ) ;
while ( ( - - parent_script_len > 0 ) & & ! IS_SLASH ( parent_script [ parent_script_len ] ) ) ;
}
/* Calculate key length */
2013-02-25 07:29:54 +00:00
key_length = cwd_len + path_length + include_path_len + 2 ;
2013-02-13 12:26:47 +00:00
if ( parent_script_len ) {
2013-02-22 06:56:05 +00:00
key_length + = parent_script_len + 1 ;
2013-02-13 12:26:47 +00:00
}
/* Generate key
* Note - the include_path must be the last element in the key ,
* since in itself , it may include colons ( which we use to separate
* different components of the key )
*/
if ( ( size_t ) key_length > = sizeof ( ZCG ( key ) ) ) {
ZCG ( key_len ) = 0 ;
return NULL ;
}
memcpy ( ZCG ( key ) , cwd , cwd_len ) ;
ZCG ( key ) [ cwd_len ] = ' : ' ;
2013-02-22 06:56:05 +00:00
memcpy ( ZCG ( key ) + cwd_len + 1 , file_handle - > filename , path_length ) ;
2013-02-13 12:26:47 +00:00
2013-02-22 06:56:05 +00:00
ZCG ( key ) [ cwd_len + 1 + path_length ] = ' : ' ;
2013-02-13 12:26:47 +00:00
2013-02-22 06:56:05 +00:00
cur_len = cwd_len + 1 + path_length + 1 ;
2013-02-13 12:26:47 +00:00
if ( parent_script_len ) {
2013-02-22 06:56:05 +00:00
memcpy ( ZCG ( key ) + cur_len , parent_script , parent_script_len ) ;
2013-02-13 12:26:47 +00:00
cur_len + = parent_script_len ;
ZCG ( key ) [ cur_len ] = ' : ' ;
cur_len + + ;
}
2013-02-22 06:56:05 +00:00
memcpy ( ZCG ( key ) + cur_len , include_path , include_path_len ) ;
2013-02-13 12:26:47 +00:00
ZCG ( key ) [ key_length ] = ' \0 ' ;
} else {
/* not use_cwd */
key_length = path_length ;
if ( ( size_t ) key_length > = sizeof ( ZCG ( key ) ) ) {
ZCG ( key_len ) = 0 ;
return NULL ;
}
2013-02-22 06:56:05 +00:00
memcpy ( ZCG ( key ) , file_handle - > filename , key_length + 1 ) ;
2013-02-13 12:26:47 +00:00
}
* key_len = ZCG ( key_len ) = key_length ;
return ZCG ( key ) ;
}
static inline char * accel_make_persistent_key ( zend_file_handle * file_handle , int * key_len TSRMLS_DC )
{
return accel_make_persistent_key_ex ( file_handle , strlen ( file_handle - > filename ) , key_len TSRMLS_CC ) ;
}
/* Adds another key for existing cached script */
static void zend_accel_add_key ( char * key , unsigned int key_length , zend_accel_hash_entry * bucket TSRMLS_DC )
{
2013-02-22 06:56:05 +00:00
if ( ! zend_accel_hash_find ( & ZCSG ( hash ) , key , key_length + 1 ) ) {
2013-02-13 12:26:47 +00:00
if ( zend_accel_hash_is_full ( & ZCSG ( hash ) ) ) {
2013-02-22 06:56:05 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " No more entries in hash table! " ) ;
2013-02-13 12:26:47 +00:00
ZSMMG ( memory_exhausted ) = 1 ;
} else {
2013-02-22 06:56:05 +00:00
char * new_key = zend_shared_alloc ( key_length + 1 ) ;
2013-02-13 12:26:47 +00:00
if ( new_key ) {
2013-02-22 06:56:05 +00:00
memcpy ( new_key , key , key_length + 1 ) ;
zend_accel_hash_update ( & ZCSG ( hash ) , new_key , key_length + 1 , 1 , bucket ) ;
2013-02-13 12:26:47 +00:00
} else {
2013-02-22 06:56:05 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " No more memory! " ) ;
2013-02-13 12:26:47 +00:00
ZSMMG ( memory_exhausted ) = 1 ;
}
}
}
}
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 )
{
zend_accel_hash_entry * bucket ;
uint memory_used ;
/* Check if script may be stored in shared memory */
2013-02-22 06:56:05 +00:00
if ( ! zend_accel_script_persistable ( new_persistent_script ) ) {
2013-02-13 12:26:47 +00:00
return new_persistent_script ;
}
/* exclusive lock */
zend_shared_alloc_lock ( TSRMLS_C ) ;
if ( zend_accel_hash_is_full ( & ZCSG ( hash ) ) ) {
2013-02-22 06:56:05 +00:00
zend_accel_error ( ACCEL_LOG_DEBUG , " No more entries in hash table! " ) ;
2013-02-13 12:26:47 +00:00
ZSMMG ( memory_exhausted ) = 1 ;
zend_accel_schedule_restart_if_necessary ( TSRMLS_C ) ;
zend_shared_alloc_unlock ( TSRMLS_C ) ;
return new_persistent_script ;
}
/* Check if we still need to put the file into the cache (may be it was
* already stored by another process . This final check is done under
* exclusive lock ) */
2013-02-22 06:56:05 +00:00
bucket = zend_accel_hash_find_entry ( & ZCSG ( hash ) , new_persistent_script - > full_path , new_persistent_script - > full_path_len + 1 ) ;
2013-02-13 12:26:47 +00:00
if ( bucket ) {
zend_persistent_script * existing_persistent_script = ( zend_persistent_script * ) bucket - > data ;
if ( ! existing_persistent_script - > corrupted ) {
if ( ! ZCG ( accel_directives ) . validate_timestamps | |
( new_persistent_script - > timestamp = = existing_persistent_script - > timestamp ) ) {
zend_accel_add_key ( key , key_length , bucket TSRMLS_CC ) ;
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
return new_persistent_script ;
}
}
/* Calculate the required memory size */
memory_used = zend_accel_script_persist_calc ( new_persistent_script , key , key_length TSRMLS_CC ) ;
/* Allocate shared memory */
ZCG ( mem ) = zend_shared_alloc ( memory_used ) ;
if ( ! ZCG ( mem ) ) {
zend_accel_error ( ACCEL_LOG_DEBUG , " No more memory! " ) ;
zend_accel_schedule_restart_if_necessary ( TSRMLS_C ) ;
if ( zend_shared_alloc_get_largest_free_block ( ) < MIN_FREE_MEMORY ) {
ZSMMG ( memory_exhausted ) = 1 ;
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
return new_persistent_script ;
}
/* cleanup after calculation */
new_persistent_script - > mem = ZCG ( mem ) ;
new_persistent_script - > size = memory_used ;
/* Copy into shared memory */
new_persistent_script = zend_accel_script_persist ( new_persistent_script , & key , key_length TSRMLS_CC ) ;
/* Consistency check */
if ( ( char * ) new_persistent_script - > mem + new_persistent_script - > size ! = ( char * ) ZCG ( mem ) ) {
zend_accel_error (
( ( char * ) new_persistent_script - > mem + new_persistent_script - > size < ( char * ) ZCG ( mem ) ) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING ,
" Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x \n " ,
new_persistent_script - > full_path ,
new_persistent_script - > mem ,
( char * ) new_persistent_script - > mem + new_persistent_script - > size ,
ZCG ( mem ) ) ;
}
new_persistent_script - > dynamic_members . checksum = zend_accel_script_checksum ( new_persistent_script ) ;
/* store script structure in the hash table */
2013-02-22 06:56:05 +00:00
bucket = zend_accel_hash_update ( & ZCSG ( hash ) , new_persistent_script - > full_path , new_persistent_script - > full_path_len + 1 , 0 , new_persistent_script ) ;
2013-02-13 12:26:47 +00:00
if ( bucket & &
( new_persistent_script - > full_path_len ! = key_length | |
memcmp ( new_persistent_script - > full_path , key , key_length ) ! = 0 ) ) {
/* link key to the same persistent script in hash table */
2013-02-22 06:56:05 +00:00
if ( ! zend_accel_hash_update ( & ZCSG ( hash ) , key , key_length + 1 , 1 , bucket ) ) {
zend_accel_error ( ACCEL_LOG_DEBUG , " No more entries in hash table! " ) ;
2013-02-13 12:26:47 +00:00
ZSMMG ( memory_exhausted ) = 1 ;
}
}
new_persistent_script - > dynamic_members . memory_consumption = ZEND_ALIGNED_SIZE ( new_persistent_script - > size ) ;
zend_shared_alloc_unlock ( TSRMLS_C ) ;
* from_shared_memory = 1 ;
return new_persistent_script ;
}
static const struct jit_auto_global_info
{
const char * name ;
size_t len ;
} jit_auto_globals_info [ ] = {
{ " _SERVER " , sizeof ( " _SERVER " ) } ,
{ " _ENV " , sizeof ( " _ENV " ) } ,
{ " _REQUEST " , sizeof ( " _REQUEST " ) } ,
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
{ " GLOBALS " , sizeof ( " GLOBALS " ) } ,
# endif
} ;
static int zend_accel_get_auto_globals ( TSRMLS_D )
{
int i , ag_size = ( sizeof ( jit_auto_globals_info ) / sizeof ( jit_auto_globals_info [ 0 ] ) ) ;
int n = 1 ;
zval * * res ;
int mask = 0 ;
for ( i = 0 ; i < ag_size ; i + + ) {
if ( zend_hash_find ( & EG ( symbol_table ) , jit_auto_globals_info [ i ] . name , jit_auto_globals_info [ i ] . len , ( void * ) & res ) = = SUCCESS ) {
mask | = n ;
}
n + = n ;
}
return mask ;
}
static void zend_accel_set_auto_globals ( int mask TSRMLS_DC )
{
int i , ag_size = ( sizeof ( jit_auto_globals_info ) / sizeof ( jit_auto_globals_info [ 0 ] ) ) ;
int n = 1 ;
for ( i = 0 ; i < ag_size ; i + + ) {
if ( mask & n ) {
zend_is_auto_global ( jit_auto_globals_info [ i ] . name , jit_auto_globals_info [ i ] . len - 1 TSRMLS_CC ) ;
}
n + = n ;
}
}
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 )
{
zend_persistent_script * new_persistent_script ;
zend_op_array * orig_active_op_array ;
HashTable * orig_function_table , * orig_class_table ;
zval * orig_user_error_handler ;
zend_op_array * op_array ;
int do_bailout = 0 ;
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
zend_uint orig_compiler_options = 0 ;
# endif
/* Try to open file */
if ( file_handle - > type = = ZEND_HANDLE_FILENAME ) {
if ( accelerator_orig_zend_stream_open_function ( file_handle - > filename , file_handle TSRMLS_CC ) = = SUCCESS ) {
/* key may be changed by zend_stream_open_function() */
if ( key = = ZCG ( key ) ) {
key_length = ZCG ( key_len ) ;
}
} else {
* op_array_p = NULL ;
2013-02-22 06:56:05 +00:00
if ( type = = ZEND_REQUIRE ) {
2013-02-13 12:26:47 +00:00
zend_message_dispatcher ( ZMSG_FAILED_REQUIRE_FOPEN , file_handle - > filename TSRMLS_CC ) ;
zend_bailout ( ) ;
} else {
zend_message_dispatcher ( ZMSG_FAILED_INCLUDE_FOPEN , file_handle - > filename TSRMLS_CC ) ;
}
return NULL ;
}
}
/* check blacklist right after ensuring that file was opened */
if ( file_handle - > opened_path & & zend_accel_blacklist_is_blacklisted ( & accel_blacklist , file_handle - > opened_path ) ) {
ZCSG ( blacklist_misses ) + + ;
* op_array_p = accelerator_orig_compile_file ( file_handle , type TSRMLS_CC ) ;
return NULL ;
}
2013-03-05 10:57:50 +00:00
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
if ( file_handle - > type = = ZEND_HANDLE_STREAM ) {
char * buf ;
size_t size , offset = 0 ;
/* Stream callbacks needs to be called in context of original
* function and class tables ( see : https : //bugs.php.net/bug.php?id=64353)
*/
if ( zend_stream_fixup ( file_handle , & buf , & size TSRMLS_CC ) = = FAILURE ) {
2013-03-05 11:46:21 +00:00
* op_array_p = NULL ;
2013-03-05 10:57:50 +00:00
return NULL ;
}
}
# endif
2013-02-13 12:26:47 +00:00
new_persistent_script = create_persistent_script ( ) ;
/* Save the original values for the op_array, function table and class table */
orig_active_op_array = CG ( active_op_array ) ;
orig_function_table = CG ( function_table ) ;
orig_class_table = CG ( class_table ) ;
orig_user_error_handler = EG ( user_error_handler ) ;
/* Override them with ours */
CG ( function_table ) = & ZCG ( function_table ) ;
EG ( class_table ) = CG ( class_table ) = & new_persistent_script - > class_table ;
EG ( user_error_handler ) = NULL ;
zend_try {
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
orig_compiler_options = CG ( compiler_options ) ;
CG ( compiler_options ) | = ZEND_COMPILE_HANDLE_OP_ARRAY ;
CG ( compiler_options ) | = ZEND_COMPILE_IGNORE_INTERNAL_CLASSES ;
CG ( compiler_options ) | = ZEND_COMPILE_DELAYED_BINDING ;
CG ( compiler_options ) | = ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION ;
# endif
op_array = * op_array_p = accelerator_orig_compile_file ( file_handle , type TSRMLS_CC ) ;
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
CG ( compiler_options ) = orig_compiler_options ;
# endif
} zend_catch {
op_array = NULL ;
do_bailout = 1 ;
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
CG ( compiler_options ) = orig_compiler_options ;
# endif
} zend_end_try ( ) ;
/* Restore originals */
CG ( active_op_array ) = orig_active_op_array ;
CG ( function_table ) = orig_function_table ;
EG ( class_table ) = CG ( class_table ) = orig_class_table ;
EG ( user_error_handler ) = orig_user_error_handler ;
if ( ! op_array ) {
/* compilation failed */
free_persistent_script ( new_persistent_script , 1 ) ;
zend_accel_free_user_functions ( & ZCG ( function_table ) TSRMLS_CC ) ;
2013-02-22 06:56:05 +00:00
if ( do_bailout ) {
2013-02-13 12:26:47 +00:00
zend_bailout ( ) ;
}
return NULL ;
}
/* Build the persistent_script structure.
Here we aren ' t sure we would store it , but we will need it
further anyway .
*/
zend_accel_move_user_functions ( & ZCG ( function_table ) , & new_persistent_script - > function_table TSRMLS_CC ) ;
new_persistent_script - > main_op_array = * op_array ;
efree ( op_array ) ; /* we have valid persistent_script, so it's safe to free op_array */
/* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
will have to ping the used auto global varaibles before execution */
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
if ( PG ( auto_globals_jit ) ) {
# else
if ( ( PG ( auto_globals_jit ) & & ! PG ( register_globals ) & & ! PG ( register_long_arrays ) ) ) {
# endif
new_persistent_script - > ping_auto_globals_mask = zend_accel_get_auto_globals ( TSRMLS_C ) ;
}
if ( ZCG ( accel_directives ) . validate_timestamps ) {
/* Obtain the file timestamps, *before* actually compiling them,
* otherwise we have a race - condition .
*/
new_persistent_script - > timestamp = zend_get_file_handle_timestamp ( file_handle TSRMLS_CC ) ;
/* If we can't obtain a timestamp (that means file is possibly socket)
* we return it but do not persist it
*/
if ( new_persistent_script - > timestamp = = 0 ) {
return new_persistent_script ;
}
new_persistent_script - > dynamic_members . revalidate = ZCSG ( revalidate_at ) ;
}
if ( file_handle - > opened_path ) {
new_persistent_script - > full_path_len = strlen ( file_handle - > opened_path ) ;
new_persistent_script - > full_path = estrndup ( file_handle - > opened_path , new_persistent_script - > full_path_len ) ;
} else {
new_persistent_script - > full_path_len = strlen ( file_handle - > filename ) ;
new_persistent_script - > full_path = estrndup ( file_handle - > filename , new_persistent_script - > full_path_len ) ;
}
new_persistent_script - > hash_value = zend_hash_func ( new_persistent_script - > full_path , new_persistent_script - > full_path_len + 1 ) ;
/* Now persistent_script structure is ready in process memory */
return cache_script_in_shared_memory ( new_persistent_script , key , key_length , from_shared_memory TSRMLS_CC ) ;
}
/* zend_compile() replacement */
static zend_op_array * persistent_compile_file ( zend_file_handle * file_handle , int type TSRMLS_DC )
{
zend_persistent_script * persistent_script = NULL ;
char * key = NULL ;
int key_length ;
int from_shared_memory ; /* if the script we've got is stored in SHM */
if ( ! file_handle - > filename | |
2013-02-25 06:35:59 +00:00
! ZCG ( enabled ) | | ! accel_startup_ok | |
2013-02-13 12:26:47 +00:00
( ! ZCG ( counted ) & & ! ZCSG ( accelerator_enabled ) ) | |
CG ( interactive ) | |
( ZCSG ( restart_in_progress ) & & accel_restart_is_active ( TSRMLS_C ) ) ) {
/* The Accelerator is disabled, act as if without the Accelerator */
return accelerator_orig_compile_file ( file_handle , type TSRMLS_CC ) ;
}
/* Make sure we only increase the currently running processes semaphore
* once each execution ( this function can be called more than once on
* each execution )
*/
if ( ! ZCG ( counted ) ) {
ZCG ( counted ) = 1 ;
accel_activate_add ( TSRMLS_C ) ;
}
/* In case this callback is called from include_once, require_once or it's
* a main FastCGI request , the key must be already calculated , and cached
* persistent script already found */
if ( ( EG ( opline_ptr ) = = NULL & &
ZCG ( cache_opline ) = = NULL & &
file_handle - > filename = = SG ( request_info ) . path_translated & &
ZCG ( cache_persistent_script ) ) | |
( EG ( opline_ptr ) & & * EG ( opline_ptr ) & &
* EG ( opline_ptr ) = = ZCG ( cache_opline ) & &
( * EG ( opline_ptr ) ) - > opcode = = ZEND_INCLUDE_OR_EVAL & &
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
( ( * EG ( opline_ptr ) ) - > extended_value = = ZEND_INCLUDE_ONCE | |
( * EG ( opline_ptr ) ) - > extended_value = = ZEND_REQUIRE_ONCE ) ) ) {
# else
( ( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval = = ZEND_INCLUDE_ONCE | |
( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval = = ZEND_REQUIRE_ONCE ) ) ) {
# endif
if ( ! ZCG ( key_len ) ) {
return accelerator_orig_compile_file ( file_handle , type TSRMLS_CC ) ;
}
/* persistent script was already found by overrifen open() or
* resolve_path ( ) callbacks */
persistent_script = ZCG ( cache_persistent_script ) ;
key = ZCG ( key ) ;
key_length = ZCG ( key_len ) ;
} else {
/* try to find cached script by key */
if ( ( key = accel_make_persistent_key ( file_handle , & key_length TSRMLS_CC ) ) = = NULL ) {
return accelerator_orig_compile_file ( file_handle , type TSRMLS_CC ) ;
}
2013-02-22 06:56:05 +00:00
persistent_script = zend_accel_hash_find ( & ZCSG ( hash ) , key , key_length + 1 ) ;
2013-02-13 12:26:47 +00:00
if ( ! persistent_script ) {
/* try to find cached script by full real path */
zend_accel_hash_entry * bucket ;
/* open file to resolve the path */
if ( file_handle - > type = = ZEND_HANDLE_FILENAME & &
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
accelerator_orig_zend_stream_open_function ( file_handle - > filename , file_handle TSRMLS_CC ) = = FAILURE ) {
# else
zend_stream_open ( file_handle - > filename , file_handle TSRMLS_CC ) = = FAILURE ) {
# endif
2013-02-22 06:56:05 +00:00
if ( type = = ZEND_REQUIRE ) {
2013-02-13 12:26:47 +00:00
zend_message_dispatcher ( ZMSG_FAILED_REQUIRE_FOPEN , file_handle - > filename TSRMLS_CC ) ;
zend_bailout ( ) ;
} else {
zend_message_dispatcher ( ZMSG_FAILED_INCLUDE_FOPEN , file_handle - > filename TSRMLS_CC ) ;
}
return NULL ;
}
if ( file_handle - > opened_path & &
2013-02-22 06:56:05 +00:00
( bucket = zend_accel_hash_find_entry ( & ZCSG ( hash ) , file_handle - > opened_path , strlen ( file_handle - > opened_path ) + 1 ) ) ! = NULL ) {
2013-02-13 12:26:47 +00:00
persistent_script = ( zend_persistent_script * ) bucket - > data ;
if ( ! ZCG ( accel_directives ) . revalidate_path & &
! persistent_script - > corrupted ) {
SHM_UNPROTECT ( ) ;
zend_shared_alloc_lock ( TSRMLS_C ) ;
zend_accel_add_key ( key , key_length , bucket TSRMLS_CC ) ;
zend_shared_alloc_unlock ( TSRMLS_C ) ;
SHM_PROTECT ( ) ;
}
}
}
}
/* clear cache */
ZCG ( cache_opline ) = NULL ;
ZCG ( cache_persistent_script ) = NULL ;
if ( persistent_script & & persistent_script - > corrupted ) {
persistent_script = NULL ;
}
SHM_UNPROTECT ( ) ;
/* If script is found then validate_timestamps if option is enabled */
if ( persistent_script & & ZCG ( accel_directives ) . validate_timestamps ) {
2013-02-22 06:56:05 +00:00
if ( validate_timestamp_and_record ( persistent_script , file_handle TSRMLS_CC ) = = FAILURE ) {
2013-02-13 12:26:47 +00:00
zend_shared_alloc_lock ( TSRMLS_C ) ;
if ( ! persistent_script - > corrupted ) {
persistent_script - > corrupted = 1 ;
persistent_script - > timestamp = 0 ;
ZSMMG ( wasted_shared_memory ) + = persistent_script - > dynamic_members . memory_consumption ;
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
persistent_script = NULL ;
}
}
/* if turned on - check the compiled script ADLER32 checksum */
if ( persistent_script & & ZCG ( accel_directives ) . consistency_checks
& & persistent_script - > dynamic_members . hits % ZCG ( accel_directives ) . consistency_checks = = 0 ) {
unsigned int checksum = zend_accel_script_checksum ( persistent_script ) ;
if ( checksum ! = persistent_script - > dynamic_members . checksum ) {
/* The checksum is wrong */
zend_accel_error ( ACCEL_LOG_INFO , " Checksum failed for '%s': expected=0x%0.8X, found=0x%0.8X " ,
persistent_script - > full_path , persistent_script - > dynamic_members . checksum , checksum ) ;
zend_shared_alloc_lock ( TSRMLS_C ) ;
if ( ! persistent_script - > corrupted ) {
persistent_script - > corrupted = 1 ;
persistent_script - > timestamp = 0 ;
ZSMMG ( wasted_shared_memory ) + = persistent_script - > dynamic_members . memory_consumption ;
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
persistent_script = NULL ;
}
}
/* If script was not found or invalidated by validate_timestamps */
if ( ! persistent_script ) {
zend_op_array * op_array ;
/* Cache miss.. */
ZCSG ( misses ) + + ;
/* No memory left. Behave like without the Accelerator */
if ( ZSMMG ( memory_exhausted ) ) {
SHM_PROTECT ( ) ;
return accelerator_orig_compile_file ( file_handle , type TSRMLS_CC ) ;
}
/* Try and cache the script and assume that it is returned from_shared_memory.
* If it isn ' t compile_and_cache_file ( ) changes the flag to 0
*/
from_shared_memory = 0 ;
persistent_script = compile_and_cache_file ( file_handle , type , key , key_length , & op_array , & from_shared_memory TSRMLS_CC ) ;
/* Something went wrong during compilation, returning NULL */
if ( ! persistent_script ) {
SHM_PROTECT ( ) ;
return op_array ; /* Presently always NULL, but not necessary in the future */
}
} else {
# if !ZEND_WIN32
ZCSG ( hits ) + + ; /* TBFixed: may lose one hit */
persistent_script - > dynamic_members . hits + + ; /* see above */
# else
InterlockedIncrement ( & ZCSG ( hits ) ) ;
InterlockedIncrement ( & persistent_script - > dynamic_members . hits ) ;
# endif
/* see bug #15471 (old BTS) */
if ( persistent_script - > full_path ) {
if ( ! EG ( opline_ptr ) | | ! * EG ( opline_ptr ) | |
( * EG ( opline_ptr ) ) - > opcode ! = ZEND_INCLUDE_OR_EVAL | |
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
( ( * EG ( opline_ptr ) ) - > extended_value ! = ZEND_INCLUDE_ONCE & &
( * EG ( opline_ptr ) ) - > extended_value ! = ZEND_REQUIRE_ONCE ) ) {
# else
( ( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval ! = ZEND_INCLUDE_ONCE & &
( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval ! = ZEND_REQUIRE_ONCE ) ) {
# endif
void * dummy = ( void * ) 1 ;
2013-02-22 06:56:05 +00:00
zend_hash_quick_add ( & EG ( included_files ) , persistent_script - > full_path , persistent_script - > full_path_len + 1 , persistent_script - > hash_value , & dummy , sizeof ( void * ) , NULL ) ;
2013-02-13 12:26:47 +00:00
}
}
zend_file_handle_dtor ( file_handle TSRMLS_CC ) ;
from_shared_memory = 1 ;
}
persistent_script - > dynamic_members . last_used = ZCG ( request_time ) ;
SHM_PROTECT ( ) ;
/* Fetch jit auto globals used in the script before execution */
if ( persistent_script - > ping_auto_globals_mask ) {
zend_accel_set_auto_globals ( persistent_script - > ping_auto_globals_mask TSRMLS_CC ) ;
}
return zend_accel_load_script ( persistent_script , from_shared_memory TSRMLS_CC ) ;
}
# if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
/* Taken from php-5.2.5 because early versions don't have correct version */
static char * accel_tsrm_realpath ( const char * path , int path_len TSRMLS_DC )
{
cwd_state new_state ;
char * real_path ;
char * cwd ;
int cwd_len ;
/* realpath("") returns CWD */
if ( ! * path ) {
new_state . cwd = ( char * ) malloc ( 1 ) ;
2013-02-18 07:34:10 +00:00
if ( ! new_state . cwd ) {
zend_accel_error ( ACCEL_LOG_ERROR , " malloc() failed " ) ;
return NULL ;
}
2013-02-13 12:26:47 +00:00
new_state . cwd [ 0 ] = ' \0 ' ;
new_state . cwd_length = 0 ;
if ( ( cwd = accel_getcwd ( & cwd_len TSRMLS_CC ) ) ! = NULL ) {
path = cwd ;
}
} else if ( ! IS_ABSOLUTE_PATH ( path , path_len ) & &
( cwd = accel_getcwd ( & cwd_len TSRMLS_CC ) ) ! = NULL ) {
new_state . cwd = zend_strndup ( cwd , cwd_len ) ;
2013-02-18 07:34:10 +00:00
if ( ! new_state . cwd ) {
zend_accel_error ( ACCEL_LOG_ERROR , " malloc() failed " ) ;
return NULL ;
}
2013-02-13 12:26:47 +00:00
new_state . cwd_length = cwd_len ;
} else {
new_state . cwd = ( char * ) malloc ( 1 ) ;
2013-02-18 07:34:10 +00:00
if ( ! new_state . cwd ) {
zend_accel_error ( ACCEL_LOG_ERROR , " malloc() failed " ) ;
return NULL ;
}
2013-02-13 12:26:47 +00:00
new_state . cwd [ 0 ] = ' \0 ' ;
new_state . cwd_length = 0 ;
}
# ifndef CWD_REALPATH
# define CWD_REALPATH 2
# endif
if ( virtual_file_ex ( & new_state , path , NULL , CWD_REALPATH ) ) {
free ( new_state . cwd ) ;
return NULL ;
}
2013-02-22 06:56:05 +00:00
real_path = emalloc ( new_state . cwd_length + 1 ) ;
memcpy ( real_path , new_state . cwd , new_state . cwd_length + 1 ) ;
2013-02-13 12:26:47 +00:00
free ( new_state . cwd ) ;
return real_path ;
}
static char * accel_php_resolve_path ( const char * filename , int filename_length , const char * path TSRMLS_DC )
{
char * resolved_path ;
char trypath [ MAXPATHLEN ] ;
const char * ptr , * end ;
int len ;
if ( ! filename ) {
return NULL ;
}
if ( * filename = = ' . ' | |
IS_ABSOLUTE_PATH ( filename , filename_length ) | |
! path | |
! * path ) {
return accel_tsrm_realpath ( filename , filename_length TSRMLS_CC ) ;
}
ptr = path ;
while ( * ptr ) {
for ( end = ptr ; * end & & * end ! = DEFAULT_DIR_SEPARATOR ; end + + ) ;
2013-02-22 06:56:05 +00:00
len = end - ptr ;
2013-02-13 12:26:47 +00:00
if ( * end ) end + + ;
if ( len + 1 + filename_length + 1 > = MAXPATHLEN ) {
ptr = end ;
continue ;
}
memcpy ( trypath , ptr , len ) ;
trypath [ len ] = ' / ' ;
2013-02-22 06:56:05 +00:00
memcpy ( trypath + len + 1 , filename , filename_length + 1 ) ;
2013-02-13 12:26:47 +00:00
ptr = end ;
2013-02-22 06:56:05 +00:00
if ( ( resolved_path = accel_tsrm_realpath ( trypath , len + 1 + filename_length TSRMLS_CC ) ) ! = NULL ) {
2013-02-13 12:26:47 +00:00
return resolved_path ;
}
} /* end provided path */
/* check in calling scripts' current working directory as a fall back case
*/
if ( EG ( in_execution ) ) {
char * exec_fname = zend_get_executed_filename ( TSRMLS_C ) ;
int exec_fname_length = strlen ( exec_fname ) ;
while ( ( - - exec_fname_length > = 0 ) & & ! IS_SLASH ( exec_fname [ exec_fname_length ] ) ) ;
if ( exec_fname & & exec_fname [ 0 ] ! = ' [ ' & &
exec_fname_length > 0 & &
exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN ) {
memcpy ( trypath , exec_fname , exec_fname_length + 1 ) ;
2013-02-22 06:56:05 +00:00
memcpy ( trypath + exec_fname_length + 1 , filename , filename_length + 1 ) ;
return accel_tsrm_realpath ( trypath , exec_fname_length + 1 + filename_length TSRMLS_CC ) ;
2013-02-13 12:26:47 +00:00
}
}
return NULL ;
}
/* zend_stream_open_function() replacement for PHP 5.2 */
static int persistent_stream_open_function ( const char * filename , zend_file_handle * handle TSRMLS_DC )
{
2013-02-25 06:35:59 +00:00
if ( ZCG ( enabled ) & & accel_startup_ok & &
2013-02-13 12:26:47 +00:00
( ZCG ( counted ) | | ZCSG ( accelerator_enabled ) ) & &
! CG ( interactive ) & &
! ZCSG ( restart_in_progress ) ) {
if ( EG ( opline_ptr ) & & * EG ( opline_ptr ) ) {
zend_op * opline = * EG ( opline_ptr ) ;
if ( opline - > opcode = = ZEND_INCLUDE_OR_EVAL & &
( opline - > op2 . u . constant . value . lval = = ZEND_INCLUDE_ONCE | |
opline - > op2 . u . constant . value . lval = = ZEND_REQUIRE_ONCE ) ) {
/* we are in include_once */
char * key = NULL ;
int key_length ;
char * resolved_path ;
zend_accel_hash_entry * bucket ;
zend_persistent_script * persistent_script ;
int filename_len ;
if ( opline - > op1 . op_type = = IS_CONST ) {
filename_len = Z_STRLEN ( opline - > op1 . u . constant ) ;
} else {
filename_len = strlen ( filename ) ;
}
handle - > filename = ( char * ) filename ;
handle - > free_filename = 0 ;
handle - > opened_path = NULL ;
/* Check if requestd file already cached (by full name) */
if ( IS_ABSOLUTE_PATH ( filename , filename_len ) & &
2013-02-22 06:56:05 +00:00
( persistent_script = zend_accel_hash_find ( & ZCSG ( hash ) , ( char * ) filename , filename_len + 1 ) ) ! = NULL & &
2013-02-13 12:26:47 +00:00
! persistent_script - > corrupted ) {
handle - > opened_path = estrndup ( persistent_script - > full_path , persistent_script - > full_path_len ) ;
handle - > type = ZEND_HANDLE_FILENAME ;
2013-02-22 06:56:05 +00:00
memcpy ( ZCG ( key ) , persistent_script - > full_path , persistent_script - > full_path_len + 1 ) ;
2013-02-13 12:26:47 +00:00
ZCG ( key_len ) = persistent_script - > full_path_len ;
ZCG ( cache_opline ) = opline ;
ZCG ( cache_persistent_script ) = persistent_script ;
return SUCCESS ;
}
/* Check if requestd file already cached (by key) */
key = accel_make_persistent_key_ex ( handle , filename_len , & key_length TSRMLS_CC ) ;
if ( ! ZCG ( accel_directives ) . revalidate_path & &
key & &
2013-02-22 06:56:05 +00:00
( persistent_script = zend_accel_hash_find ( & ZCSG ( hash ) , key , key_length + 1 ) ) ! = NULL & &
2013-02-13 12:26:47 +00:00
! persistent_script - > corrupted ) {
handle - > opened_path = estrndup ( persistent_script - > full_path , persistent_script - > full_path_len ) ;
handle - > type = ZEND_HANDLE_FILENAME ;
ZCG ( cache_opline ) = opline ;
ZCG ( cache_persistent_script ) = persistent_script ;
return SUCCESS ;
}
/* find the full real path */
resolved_path = accel_php_resolve_path ( filename , filename_len , ZCG ( include_path ) TSRMLS_CC ) ;
/* Check if requestd file already cached (by real name) */
if ( resolved_path & &
2013-02-22 06:56:05 +00:00
( bucket = zend_accel_hash_find_entry ( & ZCSG ( hash ) , resolved_path , strlen ( resolved_path ) + 1 ) ) ! = NULL ) {
2013-02-13 12:26:47 +00:00
persistent_script = ( zend_persistent_script * ) bucket - > data ;
if ( persistent_script & & ! persistent_script - > corrupted ) {
handle - > opened_path = resolved_path ;
handle - > type = ZEND_HANDLE_FILENAME ;
if ( key & & ! ZCG ( accel_directives ) . revalidate_path ) {
/* add another "key" for the same bucket */
SHM_UNPROTECT ( ) ;
zend_shared_alloc_lock ( TSRMLS_C ) ;
zend_accel_add_key ( key , key_length , bucket TSRMLS_CC ) ;
zend_shared_alloc_unlock ( TSRMLS_C ) ;
SHM_PROTECT ( ) ;
}
ZCG ( cache_opline ) = opline ;
ZCG ( cache_persistent_script ) = persistent_script ;
return SUCCESS ;
}
}
if ( resolved_path ) {
efree ( resolved_path ) ;
}
}
}
}
ZCG ( cache_opline ) = NULL ;
ZCG ( cache_persistent_script ) = NULL ;
return accelerator_orig_zend_stream_open_function ( filename , handle TSRMLS_CC ) ;
}
# else
/* zend_stream_open_function() replacement for PHP 5.3 and above */
static int persistent_stream_open_function ( const char * filename , zend_file_handle * handle TSRMLS_DC )
{
2013-02-25 06:35:59 +00:00
if ( ZCG ( enabled ) & & accel_startup_ok & &
2013-02-13 12:26:47 +00:00
( ZCG ( counted ) | | ZCSG ( accelerator_enabled ) ) & &
! CG ( interactive ) & &
! ZCSG ( restart_in_progress ) ) {
/* check if callback is called from include_once or it's a main request */
if ( ( ! EG ( opline_ptr ) & &
filename = = SG ( request_info ) . path_translated ) | |
( EG ( opline_ptr ) & &
* EG ( opline_ptr ) & &
( * EG ( opline_ptr ) ) - > opcode = = ZEND_INCLUDE_OR_EVAL & &
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
( ( * EG ( opline_ptr ) ) - > extended_value = = ZEND_INCLUDE_ONCE | |
( * EG ( opline_ptr ) ) - > extended_value = = ZEND_REQUIRE_ONCE ) ) ) {
# else
( ( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval = = ZEND_INCLUDE_ONCE | |
( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval = = ZEND_REQUIRE_ONCE ) ) ) {
# endif
/* we are in include_once or FastCGI request */
zend_persistent_script * persistent_script ;
handle - > filename = ( char * ) filename ;
handle - > free_filename = 0 ;
/* check if cached script was already found by resolve_path() */
if ( ( EG ( opline_ptr ) = = NULL & &
ZCG ( cache_opline ) = = NULL & &
ZCG ( cache_persistent_script ) ! = NULL ) | |
( EG ( opline_ptr ) & &
( ZCG ( cache_opline ) = = * EG ( opline_ptr ) ) ) ) {
persistent_script = ZCG ( cache_persistent_script ) ;
handle - > opened_path = estrndup ( persistent_script - > full_path , persistent_script - > full_path_len ) ;
handle - > type = ZEND_HANDLE_FILENAME ;
return SUCCESS ;
#if 0
} else {
/* FIXME: It looks like this part is not needed any more */
int filename_len = strlen ( filename ) ;
if ( ( IS_ABSOLUTE_PATH ( filename , filename_len ) | |
is_stream_path ( filename ) ) & &
2013-02-22 06:56:05 +00:00
( persistent_script = zend_accel_hash_find ( & ZCSG ( hash ) , ( char * ) filename , filename_len + 1 ) ) ! = NULL & &
2013-02-13 12:26:47 +00:00
! persistent_script - > corrupted ) {
handle - > opened_path = estrndup ( persistent_script - > full_path , persistent_script - > full_path_len ) ;
handle - > type = ZEND_HANDLE_FILENAME ;
2013-02-22 06:56:05 +00:00
memcpy ( ZCG ( key ) , persistent_script - > full_path , persistent_script - > full_path_len + 1 ) ;
2013-02-13 12:26:47 +00:00
ZCG ( key_len ) = persistent_script - > full_path_len ;
ZCG ( cache_opline ) = EG ( opline_ptr ) ? * EG ( opline_ptr ) : NULL ;
ZCG ( cache_persistent_script ) = EG ( opline_ptr ) ? persistent_script : NULL ;
return SUCCESS ;
}
# endif
}
}
}
ZCG ( cache_opline ) = NULL ;
ZCG ( cache_persistent_script ) = NULL ;
return accelerator_orig_zend_stream_open_function ( filename , handle TSRMLS_CC ) ;
}
/* zend_resolve_path() replacement for PHP 5.3 and above */
static char * persistent_zend_resolve_path ( const char * filename , int filename_len TSRMLS_DC )
{
2013-02-25 06:35:59 +00:00
if ( ZCG ( enabled ) & & accel_startup_ok & &
2013-02-13 12:26:47 +00:00
( ZCG ( counted ) | | ZCSG ( accelerator_enabled ) ) & &
! CG ( interactive ) & &
! ZCSG ( restart_in_progress ) ) {
/* check if callback is called from include_once or it's a main request */
if ( ( ! EG ( opline_ptr ) & &
filename = = SG ( request_info ) . path_translated ) | |
( EG ( opline_ptr ) & &
* EG ( opline_ptr ) & &
( * EG ( opline_ptr ) ) - > opcode = = ZEND_INCLUDE_OR_EVAL & &
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
( ( * EG ( opline_ptr ) ) - > extended_value = = ZEND_INCLUDE_ONCE | |
( * EG ( opline_ptr ) ) - > extended_value = = ZEND_REQUIRE_ONCE ) ) ) {
# else
( ( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval = = ZEND_INCLUDE_ONCE | |
( * EG ( opline_ptr ) ) - > op2 . u . constant . value . lval = = ZEND_REQUIRE_ONCE ) ) ) {
# endif
/* we are in include_once or FastCGI request */
zend_file_handle handle ;
char * key = NULL ;
int key_length ;
char * resolved_path ;
zend_accel_hash_entry * bucket ;
zend_persistent_script * persistent_script ;
2013-02-22 06:56:05 +00:00
2013-02-13 12:26:47 +00:00
/* Check if requestd file already cached (by full name) */
if ( ( IS_ABSOLUTE_PATH ( filename , filename_len ) | |
is_stream_path ( filename ) ) & &
2013-02-22 06:56:05 +00:00
( bucket = zend_accel_hash_find_entry ( & ZCSG ( hash ) , ( char * ) filename , filename_len + 1 ) ) ! = NULL ) {
2013-02-13 12:26:47 +00:00
persistent_script = ( zend_persistent_script * ) bucket - > data ;
if ( persistent_script & & ! persistent_script - > corrupted ) {
2013-02-22 06:56:05 +00:00
memcpy ( ZCG ( key ) , persistent_script - > full_path , persistent_script - > full_path_len + 1 ) ;
2013-02-13 12:26:47 +00:00
ZCG ( key_len ) = persistent_script - > full_path_len ;
ZCG ( cache_opline ) = EG ( opline_ptr ) ? * EG ( opline_ptr ) : NULL ;
ZCG ( cache_persistent_script ) = persistent_script ;
return estrndup ( persistent_script - > full_path , persistent_script - > full_path_len ) ;
}
}
/* Check if requestd file already cached (by key) */
handle . filename = ( char * ) filename ;
handle . free_filename = 0 ;
handle . opened_path = NULL ;
key = accel_make_persistent_key_ex ( & handle , filename_len , & key_length TSRMLS_CC ) ;
if ( ! ZCG ( accel_directives ) . revalidate_path & &
key & &
2013-02-22 06:56:05 +00:00
( persistent_script = zend_accel_hash_find ( & ZCSG ( hash ) , key , key_length + 1 ) ) ! = NULL & &
2013-02-13 12:26:47 +00:00
! persistent_script - > corrupted ) {
/* we have persistent script */
ZCG ( cache_opline ) = EG ( opline_ptr ) ? * EG ( opline_ptr ) : NULL ;
ZCG ( cache_persistent_script ) = persistent_script ;
return estrndup ( persistent_script - > full_path , persistent_script - > full_path_len ) ;
}
/* find the full real path */
resolved_path = accelerator_orig_zend_resolve_path ( filename , filename_len TSRMLS_CC ) ;
/* Check if requestd file already cached (by real path) */
if ( resolved_path & &
2013-02-22 06:56:05 +00:00
( bucket = zend_accel_hash_find_entry ( & ZCSG ( hash ) , resolved_path , strlen ( resolved_path ) + 1 ) ) ! = NULL ) {
2013-02-13 12:26:47 +00:00
persistent_script = ( zend_persistent_script * ) bucket - > data ;
if ( persistent_script & & ! persistent_script - > corrupted ) {
if ( key & & ! ZCG ( accel_directives ) . revalidate_path ) {
/* add another "key" for the same bucket */
SHM_UNPROTECT ( ) ;
zend_shared_alloc_lock ( TSRMLS_C ) ;
zend_accel_add_key ( key , key_length , bucket TSRMLS_CC ) ;
zend_shared_alloc_unlock ( TSRMLS_C ) ;
SHM_PROTECT ( ) ;
}
ZCG ( cache_opline ) = ( EG ( opline_ptr ) & & key ) ? * EG ( opline_ptr ) : NULL ;
ZCG ( cache_persistent_script ) = key ? persistent_script : NULL ;
return resolved_path ;
}
}
ZCG ( cache_opline ) = NULL ;
ZCG ( cache_persistent_script ) = NULL ;
return resolved_path ;
}
}
ZCG ( cache_opline ) = NULL ;
ZCG ( cache_persistent_script ) = NULL ;
return accelerator_orig_zend_resolve_path ( filename , filename_len TSRMLS_CC ) ;
}
# endif
static void zend_reset_cache_vars ( TSRMLS_D )
{
ZSMMG ( memory_exhausted ) = 0 ;
ZCSG ( hits ) = 0 ;
ZCSG ( misses ) = 0 ;
ZCSG ( blacklist_misses ) = 0 ;
ZSMMG ( wasted_shared_memory ) = 0 ;
ZCSG ( restart_pending ) = 0 ;
ZCSG ( force_restart_time ) = 0 ;
}
static void accel_activate ( void )
{
TSRMLS_FETCH ( ) ;
2013-02-25 06:35:59 +00:00
if ( ! ZCG ( enabled ) | | ! accel_startup_ok ) {
2013-02-13 12:26:47 +00:00
return ;
}
SHM_UNPROTECT ( ) ;
2013-02-18 09:27:42 +00:00
/* PHP-5.4 and above return "double", but we use 1 sec precision */
ZCG ( request_time ) = ( time_t ) sapi_get_request_time ( TSRMLS_C ) ;
2013-02-13 12:26:47 +00:00
ZCG ( cache_opline ) = NULL ;
ZCG ( cache_persistent_script ) = NULL ;
ZCG ( include_path_check ) = ! ZCG ( include_path_key ) ;
if ( ZCG ( counted ) ) {
# ifdef ZTS
zend_accel_error ( ACCEL_LOG_WARNING , " Stuck count for thread id %d " , tsrm_thread_id ( ) ) ;
# else
zend_accel_error ( ACCEL_LOG_WARNING , " Stuck count for pid %d " , getpid ( ) ) ;
# endif
accel_unlock_all ( TSRMLS_C ) ;
ZCG ( counted ) = 0 ;
}
if ( ZCSG ( restart_pending ) ) {
zend_shared_alloc_lock ( TSRMLS_C ) ;
if ( ZCSG ( restart_pending ) ! = 0 ) { /* check again, to ensure that the cache wasn't already cleaned by another process */
if ( accel_is_inactive ( TSRMLS_C ) = = SUCCESS ) {
zend_accel_error ( ACCEL_LOG_DEBUG , " Restarting! " ) ;
ZCSG ( restart_pending ) = 0 ;
accel_restart_enter ( TSRMLS_C ) ;
zend_reset_cache_vars ( TSRMLS_C ) ;
zend_accel_hash_clean ( & ZCSG ( hash ) ) ;
/* include_paths keeps only the first path */
if ( ZCSG ( include_paths ) . num_entries > 1 ) {
ZCSG ( include_paths ) . num_entries = 1 ;
ZCSG ( include_paths ) . num_direct_entries = 1 ;
memset ( ZCSG ( include_paths ) . hash_table , 0 , sizeof ( zend_accel_hash_entry * ) * ZCSG ( include_paths ) . max_num_entries ) ;
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 ] ;
}
# if (ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO) && !defined(ZTS)
accel_interned_strings_restore_state ( TSRMLS_C ) ;
# endif
zend_shared_alloc_restore_state ( ) ;
ZCSG ( accelerator_enabled ) = ZCSG ( cache_status_before_restart ) ;
ZCSG ( last_restart_time ) = ZCG ( request_time ) ;
accel_restart_leave ( TSRMLS_C ) ;
}
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
}
/* check if ZCG(function_table) wasn't somehow polluted on the way */
2013-02-22 06:56:05 +00:00
if ( ZCG ( internal_functions_count ) ! = zend_hash_num_elements ( & ZCG ( function_table ) ) ) {
2013-02-13 12:26:47 +00:00
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 ) ) ) ;
}
if ( ZCG ( accel_directives ) . validate_timestamps ) {
time_t now = ZCG ( request_time ) ;
if ( now > ZCSG ( revalidate_at ) + ( time_t ) ZCG ( accel_directives ) . revalidate_freq ) {
ZCSG ( revalidate_at ) = now ;
}
}
ZCG ( cwd ) = NULL ;
SHM_PROTECT ( ) ;
}
# if !ZEND_DEBUG
/* Fast Request Shutdown
* = = = = = = = = = = = = = = = = = = = = =
* Zend Memory Manager frees memory by its own . We don ' t have to free each
* allocated block separately , but we like to call all the destructors and
* callbacks in exactly the same order .
*/
static void accel_fast_hash_destroy ( HashTable * ht )
{
Bucket * p = ht - > pListHead ;
while ( p ! = NULL ) {
ht - > pDestructor ( p - > pData ) ;
p = p - > pListNext ;
}
}
static void accel_fast_zval_ptr_dtor ( zval * * zval_ptr )
{
zval * zvalue = * zval_ptr ;
2013-02-22 06:56:05 +00:00
if ( Z_DELREF_P ( zvalue ) = = 0 ) {
2013-02-13 12:26:47 +00:00
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
switch ( Z_TYPE_P ( zvalue ) & IS_CONSTANT_TYPE_MASK ) {
# else
switch ( Z_TYPE_P ( zvalue ) & ~ IS_CONSTANT_INDEX ) {
# endif
case IS_ARRAY :
case IS_CONSTANT_ARRAY : {
TSRMLS_FETCH ( ) ;
if ( zvalue - > value . ht & & ( zvalue - > value . ht ! = & EG ( symbol_table ) ) ) {
zvalue - > value . ht - > pDestructor = ( dtor_func_t ) accel_fast_zval_ptr_dtor ;
accel_fast_hash_destroy ( zvalue - > value . ht ) ;
}
}
break ;
case IS_OBJECT :
{
TSRMLS_FETCH ( ) ;
Z_OBJ_HT_P ( zvalue ) - > del_ref ( zvalue TSRMLS_CC ) ;
}
break ;
case IS_RESOURCE :
{
TSRMLS_FETCH ( ) ;
/* destroy resource */
zend_list_delete ( zvalue - > value . lval ) ;
}
break ;
case IS_LONG :
case IS_DOUBLE :
case IS_BOOL :
case IS_NULL :
case IS_STRING :
case IS_CONSTANT :
default :
return ;
break ;
}
}
}
static int accel_clean_non_persistent_function ( zend_function * function TSRMLS_DC )
{
if ( function - > type = = ZEND_INTERNAL_FUNCTION ) {
return ZEND_HASH_APPLY_STOP ;
} else {
if ( function - > op_array . static_variables ) {
function - > op_array . static_variables - > pDestructor = ( dtor_func_t ) accel_fast_zval_ptr_dtor ;
accel_fast_hash_destroy ( function - > op_array . static_variables ) ;
function - > op_array . static_variables = NULL ;
}
return ( - - ( * function - > op_array . refcount ) < = 0 ) ?
ZEND_HASH_APPLY_REMOVE :
ZEND_HASH_APPLY_KEEP ;
}
}
static int accel_cleanup_function_data ( zend_function * function TSRMLS_DC )
{
if ( function - > type = = ZEND_USER_FUNCTION ) {
if ( function - > op_array . static_variables ) {
function - > op_array . static_variables - > pDestructor = ( dtor_func_t ) accel_fast_zval_ptr_dtor ;
accel_fast_hash_destroy ( function - > op_array . static_variables ) ;
function - > op_array . static_variables = NULL ;
}
}
return 0 ;
}
static int accel_clean_non_persistent_class ( zend_class_entry * * pce TSRMLS_DC )
{
zend_class_entry * ce = * pce ;
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
return ZEND_HASH_APPLY_STOP ;
} else {
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
if ( ce - > ce_flags & ZEND_HAS_STATIC_IN_METHODS ) {
zend_hash_apply ( & ce - > function_table , ( apply_func_t ) accel_cleanup_function_data TSRMLS_CC ) ;
}
if ( ce - > static_members_table ) {
int i ;
for ( i = 0 ; i < ce - > default_static_members_count ; i + + ) {
if ( ce - > static_members_table [ i ] ) {
accel_fast_zval_ptr_dtor ( & ce - > static_members_table [ i ] ) ;
ce - > static_members_table [ i ] = NULL ;
}
}
ce - > static_members_table = NULL ;
}
# else
zend_hash_apply ( & ce - > function_table , ( apply_func_t ) accel_cleanup_function_data TSRMLS_CC ) ;
if ( ce - > static_members ) {
ce - > static_members - > pDestructor = ( dtor_func_t ) accel_fast_zval_ptr_dtor ;
accel_fast_hash_destroy ( ce - > static_members ) ;
ce - > static_members = NULL ;
}
# endif
return ZEND_HASH_APPLY_REMOVE ;
}
}
static int accel_clean_non_persistent_constant ( zend_constant * c TSRMLS_DC )
{
if ( c - > flags & CONST_PERSISTENT ) {
return ZEND_HASH_APPLY_STOP ;
} else {
interned_free ( c - > name ) ;
return ZEND_HASH_APPLY_REMOVE ;
}
}
static void zend_accel_fast_shutdown ( TSRMLS_D )
{
if ( EG ( full_tables_cleanup ) ) {
EG ( symbol_table ) . pDestructor = ( dtor_func_t ) accel_fast_zval_ptr_dtor ;
} else {
dtor_func_t old_destructor ;
if ( EG ( objects_store ) . top > 1 | | zend_hash_num_elements ( & EG ( regular_list ) ) > 0 ) {
/* We don't have to destroy all zvals if they cannot call any destructors */
old_destructor = EG ( symbol_table ) . pDestructor ;
EG ( symbol_table ) . pDestructor = ( dtor_func_t ) accel_fast_zval_ptr_dtor ;
zend_try {
zend_hash_graceful_reverse_destroy ( & EG ( symbol_table ) ) ;
} zend_end_try ( ) ;
EG ( symbol_table ) . pDestructor = old_destructor ;
}
zend_hash_init ( & EG ( symbol_table ) , 0 , NULL , NULL , 0 ) ;
old_destructor = EG ( function_table ) - > pDestructor ;
EG ( function_table ) - > pDestructor = NULL ;
zend_hash_reverse_apply ( EG ( function_table ) , ( apply_func_t ) accel_clean_non_persistent_function TSRMLS_CC ) ;
EG ( function_table ) - > pDestructor = old_destructor ;
old_destructor = EG ( class_table ) - > pDestructor ;
EG ( class_table ) - > pDestructor = NULL ;
zend_hash_reverse_apply ( EG ( class_table ) , ( apply_func_t ) accel_clean_non_persistent_class TSRMLS_CC ) ;
EG ( class_table ) - > pDestructor = old_destructor ;
old_destructor = EG ( zend_constants ) - > pDestructor ;
EG ( zend_constants ) - > pDestructor = NULL ;
zend_hash_reverse_apply ( EG ( zend_constants ) , ( apply_func_t ) accel_clean_non_persistent_constant TSRMLS_CC ) ;
EG ( zend_constants ) - > pDestructor = old_destructor ;
}
CG ( unclean_shutdown ) = 1 ;
}
# endif
static void accel_deactivate ( void )
{
/* ensure that we restore function_table and class_table
* In general , they ' re restored by persistent_compile_file ( ) , but in case
* the script is aborted abnormally , they may become messed up .
*/
TSRMLS_FETCH ( ) ;
2013-02-25 06:35:59 +00:00
if ( ! ZCG ( enabled ) | | ! accel_startup_ok ) {
2013-02-13 12:26:47 +00:00
return ;
}
zend_shared_alloc_safe_unlock ( TSRMLS_C ) ; /* be sure we didn't leave cache locked */
accel_unlock_all ( TSRMLS_C ) ;
ZCG ( counted ) = 0 ;
# if !ZEND_DEBUG
if ( ZCG ( accel_directives ) . fast_shutdown ) {
zend_accel_fast_shutdown ( TSRMLS_C ) ;
}
# endif
if ( ZCG ( cwd ) ) {
efree ( ZCG ( cwd ) ) ;
ZCG ( cwd ) = NULL ;
}
}
static int accelerator_remove_cb ( zend_extension * element1 , zend_extension * element2 )
{
( void ) element2 ; /* keep the compiler happy */
if ( ! strcmp ( element1 - > name , ACCELERATOR_PRODUCT_NAME ) ) {
element1 - > startup = NULL ;
#if 0
/* We have to call shutdown callback it to free TS resources */
element1 - > shutdown = NULL ;
# endif
element1 - > activate = NULL ;
element1 - > deactivate = NULL ;
element1 - > op_array_handler = NULL ;
# ifdef __DEBUG_MESSAGES__
fprintf ( stderr , ACCELERATOR_PRODUCT_NAME " is disabled: %s \n " , ( zps_failure_reason ? zps_failure_reason : " unknown error " ) ) ;
fflush ( stderr ) ;
# endif
}
return 0 ;
}
static void zps_startup_failure ( char * reason , char * api_reason , int ( * cb ) ( zend_extension * , zend_extension * ) TSRMLS_DC )
{
2013-02-15 09:45:42 +00:00
accel_startup_ok = 0 ;
2013-02-13 12:26:47 +00:00
zps_failure_reason = reason ;
zps_api_failure_reason = api_reason ? api_reason : reason ;
zend_llist_del_element ( & zend_extensions , NULL , ( int ( * ) ( void * , void * ) ) cb ) ;
}
static inline int accel_find_sapi ( TSRMLS_D )
{
static const char * supported_sapis [ ] = {
" apache " ,
" fastcgi " ,
2013-02-17 15:48:31 +00:00
" cli-server " ,
2013-02-13 12:26:47 +00:00
" cgi-fcgi " ,
" fpm-fcgi " ,
" isapi " ,
" apache2filter " ,
" apache2handler " ,
NULL
} ;
const char * * sapi_name ;
if ( sapi_module . name ) {
2013-02-22 06:56:05 +00:00
for ( sapi_name = supported_sapis ; * sapi_name ; sapi_name + + ) {
if ( strcmp ( sapi_module . name , * sapi_name ) = = 0 ) {
2013-02-13 12:26:47 +00:00
return SUCCESS ;
}
}
if ( ZCG ( accel_directives ) . enable_cli & &
2013-02-22 06:56:05 +00:00
strcmp ( sapi_module . name , " cli " ) = = 0 ) {
2013-02-13 12:26:47 +00:00
return SUCCESS ;
}
}
return FAILURE ;
}
static void zend_accel_init_shm ( TSRMLS_D )
{
zend_shared_alloc_lock ( TSRMLS_C ) ;
accel_shared_globals = zend_shared_alloc ( sizeof ( zend_accel_shared_globals ) ) ;
if ( ! accel_shared_globals ) {
zend_accel_error ( ACCEL_LOG_FATAL , " Insufficient shared memory! " ) ;
2013-02-19 14:07:23 +00:00
return ;
2013-02-13 12:26:47 +00:00
}
ZSMMG ( app_shared_globals ) = accel_shared_globals ;
zend_accel_hash_init ( & ZCSG ( hash ) , ZCG ( accel_directives ) . max_accelerated_files ) ;
zend_accel_hash_init ( & ZCSG ( include_paths ) , 32 ) ;
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
# ifndef ZTS
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 ) ;
ZCSG ( interned_strings ) . nTableMask = ZCSG ( interned_strings ) . nTableSize - 1 ;
ZCSG ( interned_strings ) . arBuckets = zend_shared_alloc ( ZCSG ( interned_strings ) . nTableSize * sizeof ( Bucket * ) ) ;
ZCSG ( interned_strings_start ) = zend_shared_alloc ( ( ZCG ( accel_directives ) . interned_strings_buffer * 1024 * 1024 ) ) ;
if ( ! ZCSG ( interned_strings ) . arBuckets | | ! ZCSG ( interned_strings_start ) ) {
zend_error ( E_ERROR , ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings " ) ;
}
ZCSG ( interned_strings_end ) = ZCSG ( interned_strings_start ) + ( ZCG ( accel_directives ) . interned_strings_buffer * 1024 * 1024 ) ;
ZCSG ( interned_strings_top ) = ZCSG ( interned_strings_start ) ;
# else
ZCSG ( interned_strings_start ) = ZCSG ( interned_strings_end ) = NULL ;
# endif
orig_interned_strings_start = CG ( interned_strings_start ) ;
orig_interned_strings_end = CG ( interned_strings_end ) ;
orig_new_interned_string = zend_new_interned_string ;
orig_interned_strings_snapshot = zend_interned_strings_snapshot ;
orig_interned_strings_restore = zend_interned_strings_restore ;
CG ( interned_strings_start ) = ZCSG ( interned_strings_start ) ;
CG ( interned_strings_end ) = ZCSG ( interned_strings_end ) ;
zend_new_interned_string = accel_new_interned_string_for_php ;
zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php ;
zend_interned_strings_restore = accel_interned_strings_restore_for_php ;
# ifndef ZTS
accel_use_shm_interned_strings ( TSRMLS_C ) ;
accel_interned_strings_save_state ( TSRMLS_C ) ;
# endif
# endif
zend_reset_cache_vars ( TSRMLS_C ) ;
ZCSG ( accelerator_enabled ) = 1 ;
ZCSG ( last_restart_time ) = 0 ;
ZCSG ( restart_in_progress ) = 0 ;
zend_shared_alloc_unlock ( TSRMLS_C ) ;
}
static void accel_globals_ctor ( zend_accel_globals * accel_globals TSRMLS_DC )
{
memset ( accel_globals , 0 , sizeof ( zend_accel_globals ) ) ;
zend_hash_init ( & accel_globals - > function_table , zend_hash_num_elements ( CG ( function_table ) ) , NULL , ZEND_FUNCTION_DTOR , 1 ) ;
zend_accel_copy_internal_functions ( TSRMLS_C ) ;
}
static void accel_globals_dtor ( zend_accel_globals * accel_globals TSRMLS_DC )
{
accel_globals - > function_table . pDestructor = NULL ;
zend_hash_destroy ( & accel_globals - > function_table ) ;
}
static int accel_startup ( zend_extension * extension )
{
zend_function * func ;
zend_ini_entry * ini_entry ;
TSRMLS_FETCH ( ) ;
# ifdef ZTS
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 ) ;
# else
accel_globals_ctor ( & accel_globals ) ;
# endif
# ifdef ZEND_WIN32
_setmaxstdio ( 2048 ) ; /* The default configuration is limited to 512 stdio files */
# endif
2013-02-18 07:04:58 +00:00
if ( start_accel_module ( ) = = FAILURE ) {
2013-02-15 09:45:42 +00:00
accel_startup_ok = 0 ;
2013-02-13 12:26:47 +00:00
zend_error ( E_WARNING , ACCELERATOR_PRODUCT_NAME " : module registration failed! " ) ;
return FAILURE ;
}
/* no supported SAPI found - disable acceleration and stop initalization */
2013-02-22 06:56:05 +00:00
if ( accel_find_sapi ( TSRMLS_C ) = = FAILURE ) {
2013-02-15 09:45:42 +00:00
accel_startup_ok = 0 ;
2013-02-14 09:19:06 +00:00
if ( ! ZCG ( accel_directives ) . enable_cli & &
2013-02-22 06:56:05 +00:00
strcmp ( sapi_module . name , " cli " ) = = 0 ) {
2013-02-14 09:19:06 +00:00
zps_startup_failure ( " Opcode Caching is disabled for CLI " , NULL , accelerator_remove_cb TSRMLS_CC ) ;
} else {
zps_startup_failure ( " Opcode Caching is only supported in Apache, ISAPI, FPM and FastCGI SAPIs " , NULL , accelerator_remove_cb TSRMLS_CC ) ;
}
2013-02-13 12:26:47 +00:00
return SUCCESS ;
}
if ( ZCG ( enabled ) = = 0 ) {
return SUCCESS ;
}
/********************************************/
/* End of non-SHM dependent initializations */
/********************************************/
switch ( zend_shared_alloc_startup ( ZCG ( accel_directives ) . memory_consumption ) ) {
case ALLOC_SUCCESS :
zend_accel_init_shm ( TSRMLS_C ) ;
break ;
case ALLOC_FAILURE :
2013-02-15 09:45:42 +00:00
accel_startup_ok = 0 ;
2013-02-22 06:56:05 +00:00
zend_accel_error ( ACCEL_LOG_FATAL , " Failure to initialize shared memory structures - probably not enough shared memory. " ) ;
2013-02-13 12:26:47 +00:00
return SUCCESS ;
case SUCCESSFULLY_REATTACHED :
accel_shared_globals = ( zend_accel_shared_globals * ) ZSMMG ( app_shared_globals ) ;
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
zend_shared_alloc_lock ( TSRMLS_C ) ;
orig_interned_strings_start = CG ( interned_strings_start ) ;
orig_interned_strings_end = CG ( interned_strings_end ) ;
orig_new_interned_string = zend_new_interned_string ;
orig_interned_strings_snapshot = zend_interned_strings_snapshot ;
orig_interned_strings_restore = zend_interned_strings_restore ;
CG ( interned_strings_start ) = ZCSG ( interned_strings_start ) ;
CG ( interned_strings_end ) = ZCSG ( interned_strings_end ) ;
zend_new_interned_string = accel_new_interned_string_for_php ;
zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php ;
zend_interned_strings_restore = accel_interned_strings_restore_for_php ;
# ifndef ZTS
accel_use_shm_interned_strings ( TSRMLS_C ) ;
# endif
zend_shared_alloc_unlock ( TSRMLS_C ) ;
# endif
break ;
case FAILED_REATTACHED :
2013-02-15 09:45:42 +00:00
accel_startup_ok = 0 ;
2013-02-22 06:56:05 +00:00
zend_accel_error ( ACCEL_LOG_FATAL , " Failure to initialize shared memory structures - can not reattach to exiting shared memory. " ) ;
2013-02-13 12:26:47 +00:00
return SUCCESS ;
break ;
}
/* from this point further, shared memory is supposed to be OK */
/* Override compiler */
accelerator_orig_compile_file = zend_compile_file ;
zend_compile_file = persistent_compile_file ;
/* Override stream opener function (to eliminate open() call caused by
* include / require statements ) */
accelerator_orig_zend_stream_open_function = zend_stream_open_function ;
zend_stream_open_function = persistent_stream_open_function ;
# if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
/* Override path resolver function (to eliminate stat() calls caused by
* include_once / require_once statements */
accelerator_orig_zend_resolve_path = zend_resolve_path ;
zend_resolve_path = persistent_zend_resolve_path ;
# endif
2013-02-22 06:56:05 +00:00
if ( ZCG ( accel_directives ) . validate_timestamps ) {
2013-02-13 12:26:47 +00:00
ZCSG ( revalidate_at ) = zend_accel_get_time ( ) + ZCG ( accel_directives ) . revalidate_freq ;
}
/* Override chdir() function */
if ( zend_hash_find ( CG ( function_table ) , " chdir " , sizeof ( " chdir " ) , ( void * * ) & func ) = = SUCCESS & &
func - > type = = ZEND_INTERNAL_FUNCTION ) {
orig_chdir = func - > internal_function . handler ;
func - > internal_function . handler = ZEND_FN ( accel_chdir ) ;
}
ZCG ( cwd ) = NULL ;
/* Override "include_path" modifier callback */
2013-02-22 06:56:05 +00:00
if ( zend_hash_find ( EG ( ini_directives ) , " include_path " , sizeof ( " include_path " ) , ( void * * ) & ini_entry ) = = SUCCESS ) {
2013-02-13 12:26:47 +00:00
ZCG ( include_path ) = INI_STR ( " include_path " ) ;
ZCG ( include_path_key ) = NULL ;
if ( ZCG ( include_path ) & & * ZCG ( include_path ) ) {
ZCG ( include_path_len ) = strlen ( ZCG ( include_path ) ) ;
if ( ! zend_accel_hash_is_full ( & ZCSG ( include_paths ) ) ) {
char * key ;
zend_shared_alloc_lock ( TSRMLS_C ) ;
key = zend_shared_alloc ( ZCG ( include_path_len ) + 2 ) ;
if ( key ) {
memcpy ( key , ZCG ( include_path ) , ZCG ( include_path_len ) + 1 ) ;
key [ ZCG ( include_path_len ) + 1 ] = ' A ' + ZCSG ( include_paths ) . num_entries ;
ZCG ( include_path_key ) = key + ZCG ( include_path_len ) + 1 ;
zend_accel_hash_update ( & ZCSG ( include_paths ) , key , ZCG ( include_path_len ) + 1 , 0 , ZCG ( include_path_key ) ) ;
}
zend_shared_alloc_unlock ( TSRMLS_C ) ;
}
} else {
ZCG ( include_path ) = " " ;
ZCG ( include_path_len ) = 0 ;
}
orig_include_path_on_modify = ini_entry - > on_modify ;
ini_entry - > on_modify = accel_include_path_on_modify ;
}
zend_shared_alloc_lock ( TSRMLS_C ) ;
zend_shared_alloc_save_state ( ) ;
zend_shared_alloc_unlock ( TSRMLS_C ) ;
SHM_PROTECT ( ) ;
2013-02-15 09:45:42 +00:00
accel_startup_ok = 1 ;
2013-02-13 12:26:47 +00:00
/* Override file_exists(), is_file() and is_readable() */
zend_accel_override_file_functions ( TSRMLS_C ) ;
#if 0
/* FIXME: We probably don't need it here */
zend_accel_copy_internal_functions ( TSRMLS_C ) ;
# endif
return SUCCESS ;
}
static void accel_free_ts_resources ( )
{
# ifndef ZTS
accel_globals_dtor ( & accel_globals ) ;
# else
ts_free_id ( accel_globals_id ) ;
# endif
}
static void accel_shutdown ( zend_extension * extension )
{
zend_ini_entry * ini_entry ;
TSRMLS_FETCH ( ) ;
( void ) extension ; /* keep the compiler happy */
zend_accel_blacklist_shutdown ( & accel_blacklist ) ;
2013-02-25 06:35:59 +00:00
if ( ! ZCG ( enabled ) | | ! accel_startup_ok ) {
2013-02-13 12:26:47 +00:00
accel_free_ts_resources ( ) ;
return ;
}
accel_free_ts_resources ( ) ;
zend_shared_alloc_shutdown ( ) ;
zend_compile_file = accelerator_orig_compile_file ;
2013-02-22 06:56:05 +00:00
if ( zend_hash_find ( EG ( ini_directives ) , " include_path " , sizeof ( " include_path " ) , ( void * * ) & ini_entry ) = = SUCCESS ) {
2013-02-13 12:26:47 +00:00
ini_entry - > on_modify = orig_include_path_on_modify ;
}
# if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
CG ( interned_strings_start ) = orig_interned_strings_start ;
CG ( interned_strings_end ) = orig_interned_strings_end ;
zend_new_interned_string = orig_new_interned_string ;
zend_interned_strings_snapshot = orig_interned_strings_snapshot ;
zend_interned_strings_restore = orig_interned_strings_restore ;
# endif
}
void zend_accel_schedule_restart ( TSRMLS_D )
{
if ( ZCSG ( restart_pending ) ) {
/* don't schedule twice */
return ;
}
zend_accel_error ( ACCEL_LOG_DEBUG , " Restart Scheduled! " ) ;
ZCSG ( restart_pending ) = 1 ;
ZCSG ( cache_status_before_restart ) = ZCSG ( accelerator_enabled ) ;
ZCSG ( accelerator_enabled ) = 0 ;
if ( ZCG ( accel_directives ) . force_restart_timeout ) {
ZCSG ( force_restart_time ) = zend_accel_get_time ( ) + ZCG ( accel_directives ) . force_restart_timeout ;
} else {
ZCSG ( force_restart_time ) = 0 ;
}
}
/* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
# ifdef ZEND_WIN32
# define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub(TSRMLS_C)
# else
# define accel_deactivate_now() accel_deactivate_sub(TSRMLS_C)
# endif
/* ensures it is OK to read SHM
if it ' s not OK ( restart in progress ) returns FAILURE
if OK returns SUCCESS
MUST call accelerator_shm_read_unlock after done lock operationss
*/
int accelerator_shm_read_lock ( TSRMLS_D )
{
2013-02-22 06:56:05 +00:00
if ( ZCG ( counted ) ) {
2013-02-13 12:26:47 +00:00
/* counted means we are holding read lock for SHM, so that nothing bad can happen */
return SUCCESS ;
} else {
/* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
or is in progress now */
accel_activate_add ( TSRMLS_C ) ; /* acquire usage lock */
/* Now if we weren't inside restart, restart would not begin until we remove usage lock */
2013-02-22 06:56:05 +00:00
if ( ZCSG ( restart_in_progress ) ) {
2013-02-13 12:26:47 +00:00
/* we already were inside restart this means it's not safe to touch shm */
accel_deactivate_now ( ) ; /* drop usage lock */
return FAILURE ;
}
}
return SUCCESS ;
}
/* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
void accelerator_shm_read_unlock ( TSRMLS_D )
{
2013-02-22 06:56:05 +00:00
if ( ! ZCG ( counted ) ) {
2013-02-13 12:26:47 +00:00
/* counted is 0 - meaning we had to readlock manually, release readlock now */
accel_deactivate_now ( ) ;
}
}
static void accel_op_array_handler ( zend_op_array * op_array )
{
TSRMLS_FETCH ( ) ;
2013-02-25 06:35:59 +00:00
if ( ZCG ( enabled ) & & accel_startup_ok & & ZCSG ( accelerator_enabled ) ) {
2013-02-13 12:26:47 +00:00
zend_optimizer ( op_array TSRMLS_CC ) ;
}
}
ZEND_EXT_API zend_extension zend_extension_entry = {
ACCELERATOR_PRODUCT_NAME , /* name */
ACCELERATOR_VERSION , /* version */
" Zend Technologies " , /* author */
" http://www.zend.com/ " , /* URL */
" Copyright (c) 1999-2013 " , /* copyright */
accel_startup , /* startup */
accel_shutdown , /* shutdown */
accel_activate , /* per-script activation */
accel_deactivate , /* per-script deactivation */
NULL , /* message handler */
accel_op_array_handler , /* op_array handler */
NULL , /* extended statement handler */
NULL , /* extended fcall begin handler */
NULL , /* extended fcall end handler */
NULL , /* op_array ctor */
NULL , /* op_array dtor */
STANDARD_ZEND_EXTENSION_PROPERTIES
} ;