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