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