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