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