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