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