/src/php-src/ext/opcache/zend_accelerator_module.c
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend OPcache | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright (c) 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 | | | https://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@php.net> | |
16 | | | Zeev Suraski <zeev@php.net> | |
17 | | | Stanislav Malyshev <stas@zend.com> | |
18 | | | Dmitry Stogov <dmitry@php.net> | |
19 | | +----------------------------------------------------------------------+ |
20 | | */ |
21 | | |
22 | | #include <time.h> |
23 | | |
24 | | #include "php.h" |
25 | | #include "ZendAccelerator.h" |
26 | | #include "zend_API.h" |
27 | | #include "zend_closures.h" |
28 | | #include "zend_extensions.h" |
29 | | #include "zend_modules.h" |
30 | | #include "zend_shared_alloc.h" |
31 | | #include "zend_accelerator_blacklist.h" |
32 | | #include "zend_file_cache.h" |
33 | | #include "php_ini.h" |
34 | | #include "SAPI.h" |
35 | | #include "zend_virtual_cwd.h" |
36 | | #include "ext/standard/info.h" |
37 | | #include "ext/date/php_date.h" |
38 | | #include "opcache_arginfo.h" |
39 | | |
40 | | #ifdef HAVE_JIT |
41 | | #include "jit/zend_jit.h" |
42 | | #endif |
43 | | |
44 | 0 | #define STRING_NOT_NULL(s) (NULL == (s)?"":s) |
45 | 16 | #define MIN_ACCEL_FILES 200 |
46 | 16 | #define MAX_ACCEL_FILES 1000000 |
47 | | /* Max value of opcache.interned_strings_buffer */ |
48 | 16 | #define MAX_INTERNED_STRINGS_BUFFER_SIZE ((zend_long)MIN( \ |
49 | 16 | MIN( \ |
50 | 16 | /* STRTAB_STR_TO_POS() must not overflow (zend_string_table_pos_t) */ \ |
51 | 16 | (ZEND_STRING_TABLE_POS_MAX - sizeof(zend_string_table)) / (1024 * 1024 / ZEND_STRING_TABLE_POS_ALIGNMENT), \ |
52 | 16 | /* nTableMask must not overflow (uint32_t) */ \ |
53 | 16 | UINT32_MAX / (32 * 1024 * sizeof(zend_string_table_pos_t)) \ |
54 | 16 | ), \ |
55 | 16 | /* SHM allocation must not overflow (size_t) */ \ |
56 | 16 | (SIZE_MAX - sizeof(zend_accel_shared_globals)) / (1024 * 1024) \ |
57 | 16 | )) |
58 | | #define TOKENTOSTR(X) #X |
59 | | |
60 | | static zif_handler orig_file_exists = NULL; |
61 | | static zif_handler orig_is_file = NULL; |
62 | | static zif_handler orig_is_readable = NULL; |
63 | | |
64 | | static bool validate_api_restriction(void) |
65 | 70.8k | { |
66 | 70.8k | if (ZCG(accel_directives).restrict_api && *ZCG(accel_directives).restrict_api) { |
67 | 0 | size_t len = strlen(ZCG(accel_directives).restrict_api); |
68 | |
|
69 | 0 | if (!SG(request_info).path_translated || |
70 | 0 | strlen(SG(request_info).path_translated) < len || |
71 | 0 | memcmp(SG(request_info).path_translated, ZCG(accel_directives).restrict_api, len) != 0) { |
72 | 0 | zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " API is restricted by \"restrict_api\" configuration directive"); |
73 | 0 | return false; |
74 | 0 | } |
75 | 0 | } |
76 | 70.8k | return true; |
77 | 70.8k | } |
78 | | |
79 | | static ZEND_INI_MH(OnUpdateMemoryConsumption) |
80 | 16 | { |
81 | 16 | if (accel_startup_ok) { |
82 | 0 | if (strcmp(sapi_module.name, "fpm-fcgi") == 0) { |
83 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption cannot be changed when OPcache is already set up. Are you using php_admin_value[opcache.memory_consumption] in an individual pool's configuration?\n"); |
84 | 0 | } else { |
85 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption cannot be changed when OPcache is already set up.\n"); |
86 | 0 | } |
87 | 0 | return FAILURE; |
88 | 0 | } |
89 | | |
90 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
91 | 16 | zend_long memsize = atoi(ZSTR_VAL(new_value)); |
92 | | /* sanity check we must use at least 8 MB */ |
93 | 16 | if (memsize < 8) { |
94 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption is set below the required 8MB.\n"); |
95 | 0 | return FAILURE; |
96 | 0 | } |
97 | 16 | if (UNEXPECTED(memsize > ZEND_LONG_MAX / (1024 * 1024))) { |
98 | 0 | *p = ZEND_LONG_MAX & ~(1024 * 1024 - 1); |
99 | 16 | } else { |
100 | 16 | *p = memsize * (1024 * 1024); |
101 | 16 | } |
102 | 16 | return SUCCESS; |
103 | 16 | } |
104 | | |
105 | | static ZEND_INI_MH(OnUpdateInternedStringsBuffer) |
106 | 16 | { |
107 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
108 | 16 | zend_long size = zend_ini_parse_quantity_warn(new_value, entry->name); |
109 | | |
110 | 16 | if (size < 0) { |
111 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer must be greater than or equal to 0, " ZEND_LONG_FMT " given.\n", size); |
112 | 0 | return FAILURE; |
113 | 0 | } |
114 | 16 | if (size > MAX_INTERNED_STRINGS_BUFFER_SIZE) { |
115 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer must be less than or equal to " ZEND_LONG_FMT ", " ZEND_LONG_FMT " given.\n", MAX_INTERNED_STRINGS_BUFFER_SIZE, size); |
116 | 0 | return FAILURE; |
117 | 0 | } |
118 | | |
119 | 16 | *p = size; |
120 | | |
121 | 16 | return SUCCESS; |
122 | 16 | } |
123 | | |
124 | | static ZEND_INI_MH(OnUpdateMaxAcceleratedFiles) |
125 | 16 | { |
126 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
127 | 16 | zend_long size = atoi(ZSTR_VAL(new_value)); |
128 | | /* sanity check we must use a value between MIN_ACCEL_FILES and MAX_ACCEL_FILES */ |
129 | 16 | if (size < MIN_ACCEL_FILES) { |
130 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set below the required minimum (%d).\n", MIN_ACCEL_FILES); |
131 | 0 | return FAILURE; |
132 | 0 | } |
133 | 16 | if (size > MAX_ACCEL_FILES) { |
134 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set above the limit (%d).\n", MAX_ACCEL_FILES); |
135 | 0 | return FAILURE; |
136 | 0 | } |
137 | 16 | *p = size; |
138 | 16 | return SUCCESS; |
139 | 16 | } |
140 | | |
141 | | static ZEND_INI_MH(OnUpdateMaxWastedPercentage) |
142 | 16 | { |
143 | 16 | double *p = (double *) ZEND_INI_GET_ADDR(); |
144 | 16 | zend_long percentage = atoi(ZSTR_VAL(new_value)); |
145 | | |
146 | 16 | if (percentage <= 0 || percentage > 50) { |
147 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_wasted_percentage must be set between 1 and 50.\n"); |
148 | 0 | return FAILURE; |
149 | 0 | } |
150 | 16 | *p = (double)percentage / 100.0; |
151 | 16 | return SUCCESS; |
152 | 16 | } |
153 | | |
154 | | static ZEND_INI_MH(OnEnable) |
155 | 16 | { |
156 | 16 | if (stage == ZEND_INI_STAGE_STARTUP || |
157 | 0 | stage == ZEND_INI_STAGE_SHUTDOWN || |
158 | 16 | stage == ZEND_INI_STAGE_DEACTIVATE) { |
159 | 16 | return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); |
160 | 16 | } else { |
161 | | /* It may be only temporarily disabled */ |
162 | 0 | bool *p = (bool *) ZEND_INI_GET_ADDR(); |
163 | 0 | if (zend_ini_parse_bool(new_value)) { |
164 | 0 | if (*p) { |
165 | | /* Do not warn if OPcache is enabled, as the update would be a noop anyways. */ |
166 | 0 | return SUCCESS; |
167 | 0 | } |
168 | | |
169 | 0 | if (stage == ZEND_INI_STAGE_ACTIVATE) { |
170 | 0 | if (strcmp(sapi_module.name, "fpm-fcgi") == 0) { |
171 | 0 | zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporarily enabled. Are you using php_admin_value[opcache.enable]=1 in an individual pool's configuration?"); |
172 | 0 | } else { |
173 | 0 | zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporarily enabled (it may be only disabled until the end of request)"); |
174 | 0 | } |
175 | 0 | } else { |
176 | 0 | zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporarily enabled (it may be only disabled until the end of request)"); |
177 | 0 | } |
178 | 0 | return FAILURE; |
179 | 0 | } else { |
180 | 0 | *p = false; |
181 | 0 | ZCG(accelerator_enabled) = false; |
182 | 0 | return SUCCESS; |
183 | 0 | } |
184 | 0 | } |
185 | 16 | } |
186 | | |
187 | | static ZEND_INI_MH(OnUpdateFileCache) |
188 | 16 | { |
189 | 16 | if (new_value) { |
190 | 0 | if (!ZSTR_LEN(new_value)) { |
191 | 0 | new_value = NULL; |
192 | 0 | } |
193 | 0 | } |
194 | 16 | OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); |
195 | 16 | return SUCCESS; |
196 | 16 | } |
197 | | |
198 | | #ifdef HAVE_JIT |
199 | | static ZEND_INI_MH(OnUpdateJit) |
200 | 141k | { |
201 | 141k | if (zend_jit_config(new_value, stage) == SUCCESS) { |
202 | 16 | return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); |
203 | 16 | } |
204 | 141k | return FAILURE; |
205 | 141k | } |
206 | | |
207 | | static ZEND_INI_MH(OnUpdateJitDebug) |
208 | 16 | { |
209 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
210 | 16 | zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); |
211 | | |
212 | 16 | if (zend_jit_debug_config(*p, val, stage) == SUCCESS) { |
213 | 16 | *p = val; |
214 | 16 | return SUCCESS; |
215 | 16 | } |
216 | 0 | return FAILURE; |
217 | 16 | } |
218 | | |
219 | | static ZEND_INI_MH(OnUpdateCounter) |
220 | 96 | { |
221 | 96 | zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); |
222 | 96 | if (val >= 0 && val < 256) { |
223 | 96 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
224 | 96 | *p = val; |
225 | 96 | return SUCCESS; |
226 | 96 | } |
227 | 0 | zend_error(E_WARNING, "Invalid \"%s\" setting; using default value instead. Should be between 0 and 255", ZSTR_VAL(entry->name)); |
228 | 0 | return FAILURE; |
229 | 96 | } |
230 | | |
231 | | static ZEND_INI_MH(OnUpdateUnrollC) |
232 | 16 | { |
233 | 16 | zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); |
234 | 16 | if (val > 0 && val < ZEND_JIT_TRACE_MAX_CALL_DEPTH) { |
235 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
236 | 16 | *p = val; |
237 | 16 | return SUCCESS; |
238 | 16 | } |
239 | 0 | zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 1 and %d", ZSTR_VAL(entry->name), |
240 | 0 | ZEND_JIT_TRACE_MAX_CALL_DEPTH); |
241 | 0 | return FAILURE; |
242 | 16 | } |
243 | | |
244 | | static ZEND_INI_MH(OnUpdateUnrollR) |
245 | 16 | { |
246 | 16 | zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); |
247 | 16 | if (val >= 0 && val < ZEND_JIT_TRACE_MAX_RET_DEPTH) { |
248 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
249 | 16 | *p = val; |
250 | 16 | return SUCCESS; |
251 | 16 | } |
252 | 0 | zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 0 and %d", ZSTR_VAL(entry->name), |
253 | 0 | ZEND_JIT_TRACE_MAX_RET_DEPTH); |
254 | 0 | return FAILURE; |
255 | 16 | } |
256 | | |
257 | | static ZEND_INI_MH(OnUpdateUnrollL) |
258 | 16 | { |
259 | 16 | zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); |
260 | 16 | if (val > 0 && val < ZEND_JIT_TRACE_MAX_LOOPS_UNROLL) { |
261 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
262 | 16 | *p = val; |
263 | 16 | return SUCCESS; |
264 | 16 | } |
265 | 0 | zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 1 and %d", ZSTR_VAL(entry->name), |
266 | 0 | ZEND_JIT_TRACE_MAX_LOOPS_UNROLL); |
267 | 0 | return FAILURE; |
268 | 16 | } |
269 | | |
270 | | static ZEND_INI_MH(OnUpdateMaxTraceLength) |
271 | 16 | { |
272 | 16 | zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); |
273 | 16 | if (val > 3 && val <= ZEND_JIT_TRACE_MAX_LENGTH) { |
274 | 16 | zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); |
275 | 16 | *p = val; |
276 | 16 | return SUCCESS; |
277 | 16 | } |
278 | 0 | zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 4 and %d", ZSTR_VAL(entry->name), |
279 | 0 | ZEND_JIT_TRACE_MAX_LENGTH); |
280 | 0 | return FAILURE; |
281 | 16 | } |
282 | | #endif |
283 | | |
284 | | ZEND_INI_BEGIN() |
285 | | STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_ALL, OnEnable, enabled , zend_accel_globals, accel_globals) |
286 | | STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals) |
287 | | STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals) |
288 | | STD_PHP_INI_BOOLEAN("opcache.validate_permission", "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_permission, zend_accel_globals, accel_globals) |
289 | | #ifndef ZEND_WIN32 |
290 | | STD_PHP_INI_BOOLEAN("opcache.validate_root" , "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_root , zend_accel_globals, accel_globals) |
291 | | #endif |
292 | | STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals) |
293 | | STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals) |
294 | | |
295 | | STD_PHP_INI_ENTRY("opcache.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals) |
296 | | STD_PHP_INI_ENTRY("opcache.memory_consumption" , "128" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals) |
297 | | STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "8" , PHP_INI_SYSTEM, OnUpdateInternedStringsBuffer, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals) |
298 | | STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "10000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals) |
299 | | STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals) |
300 | | STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals) |
301 | | STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals) |
302 | | STD_PHP_INI_ENTRY("opcache.file_update_protection", "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.file_update_protection, zend_accel_globals, accel_globals) |
303 | | STD_PHP_INI_ENTRY("opcache.preferred_memory_model", "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.memory_model, zend_accel_globals, accel_globals) |
304 | | STD_PHP_INI_ENTRY("opcache.blacklist_filename" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.user_blacklist_filename, zend_accel_globals, accel_globals) |
305 | | STD_PHP_INI_ENTRY("opcache.max_file_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.max_file_size, zend_accel_globals, accel_globals) |
306 | | |
307 | | STD_PHP_INI_BOOLEAN("opcache.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals) |
308 | | STD_PHP_INI_BOOLEAN("opcache.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals) |
309 | | STD_PHP_INI_BOOLEAN("opcache.record_warnings" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.record_warnings, zend_accel_globals, accel_globals) |
310 | | |
311 | | STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals) |
312 | | STD_PHP_INI_ENTRY("opcache.opt_debug_level" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.opt_debug_level, zend_accel_globals, accel_globals) |
313 | | STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals) |
314 | | STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals) |
315 | | STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals) |
316 | | STD_PHP_INI_ENTRY("opcache.restrict_api" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.restrict_api, zend_accel_globals, accel_globals) |
317 | | |
318 | | #ifndef ZEND_WIN32 |
319 | | STD_PHP_INI_ENTRY("opcache.lockfile_path" , "/tmp" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.lockfile_path, zend_accel_globals, accel_globals) |
320 | | #else |
321 | | STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) |
322 | | #endif |
323 | | |
324 | | STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals) |
325 | | STD_PHP_INI_BOOLEAN("opcache.file_cache_read_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_read_only, zend_accel_globals, accel_globals) |
326 | | STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) |
327 | | STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) |
328 | | #if ENABLE_FILE_CACHE_FALLBACK |
329 | | STD_PHP_INI_BOOLEAN("opcache.file_cache_fallback" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_fallback, zend_accel_globals, accel_globals) |
330 | | #endif |
331 | | #ifdef HAVE_HUGE_CODE_PAGES |
332 | | STD_PHP_INI_BOOLEAN("opcache.huge_code_pages" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.huge_code_pages, zend_accel_globals, accel_globals) |
333 | | #endif |
334 | | STD_PHP_INI_ENTRY("opcache.preload" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload, zend_accel_globals, accel_globals) |
335 | | #ifndef ZEND_WIN32 |
336 | | STD_PHP_INI_ENTRY("opcache.preload_user" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload_user, zend_accel_globals, accel_globals) |
337 | | #endif |
338 | | #ifdef ZEND_WIN32 |
339 | | STD_PHP_INI_ENTRY("opcache.cache_id" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.cache_id, zend_accel_globals, accel_globals) |
340 | | #endif |
341 | | #ifdef HAVE_JIT |
342 | | STD_PHP_INI_ENTRY("opcache.jit" , "disable", PHP_INI_ALL, OnUpdateJit, options, zend_jit_globals, jit_globals) |
343 | | STD_PHP_INI_ENTRY("opcache.jit_buffer_size" , ZEND_JIT_DEFAULT_BUFFER_SIZE, PHP_INI_SYSTEM, OnUpdateLong, buffer_size, zend_jit_globals, jit_globals) |
344 | | STD_PHP_INI_ENTRY("opcache.jit_debug" , "0", PHP_INI_ALL, OnUpdateJitDebug, debug, zend_jit_globals, jit_globals) |
345 | | STD_PHP_INI_ENTRY("opcache.jit_bisect_limit" , "0", PHP_INI_ALL, OnUpdateLong, bisect_limit, zend_jit_globals, jit_globals) |
346 | | STD_PHP_INI_ENTRY("opcache.jit_prof_threshold" , "0.005", PHP_INI_ALL, OnUpdateReal, prof_threshold, zend_jit_globals, jit_globals) |
347 | | STD_PHP_INI_ENTRY("opcache.jit_max_root_traces" , "1024", PHP_INI_SYSTEM, OnUpdateLong, max_root_traces, zend_jit_globals, jit_globals) |
348 | | STD_PHP_INI_ENTRY("opcache.jit_max_side_traces" , "128", PHP_INI_SYSTEM, OnUpdateLong, max_side_traces, zend_jit_globals, jit_globals) |
349 | | STD_PHP_INI_ENTRY("opcache.jit_max_exit_counters" , "8192", PHP_INI_SYSTEM, OnUpdateLong, max_exit_counters, zend_jit_globals, jit_globals) |
350 | | /* Default value should be a prime number, to reduce the chances of loop iterations being a factor of opcache.jit_hot_loop */ |
351 | | STD_PHP_INI_ENTRY("opcache.jit_hot_loop" , "61", PHP_INI_SYSTEM, OnUpdateCounter, hot_loop, zend_jit_globals, jit_globals) |
352 | | STD_PHP_INI_ENTRY("opcache.jit_hot_func" , "127", PHP_INI_SYSTEM, OnUpdateCounter, hot_func, zend_jit_globals, jit_globals) |
353 | | STD_PHP_INI_ENTRY("opcache.jit_hot_return" , "8", PHP_INI_SYSTEM, OnUpdateCounter, hot_return, zend_jit_globals, jit_globals) |
354 | | STD_PHP_INI_ENTRY("opcache.jit_hot_side_exit" , "8", PHP_INI_ALL, OnUpdateCounter, hot_side_exit, zend_jit_globals, jit_globals) |
355 | | STD_PHP_INI_ENTRY("opcache.jit_blacklist_root_trace" , "16", PHP_INI_ALL, OnUpdateCounter, blacklist_root_trace, zend_jit_globals, jit_globals) |
356 | | STD_PHP_INI_ENTRY("opcache.jit_blacklist_side_trace" , "8", PHP_INI_ALL, OnUpdateCounter, blacklist_side_trace, zend_jit_globals, jit_globals) |
357 | | STD_PHP_INI_ENTRY("opcache.jit_max_loop_unrolls" , "8", PHP_INI_ALL, OnUpdateUnrollL, max_loop_unrolls, zend_jit_globals, jit_globals) |
358 | | STD_PHP_INI_ENTRY("opcache.jit_max_recursive_calls" , "2", PHP_INI_ALL, OnUpdateUnrollC, max_recursive_calls, zend_jit_globals, jit_globals) |
359 | | STD_PHP_INI_ENTRY("opcache.jit_max_recursive_returns" , "2", PHP_INI_ALL, OnUpdateUnrollR, max_recursive_returns, zend_jit_globals, jit_globals) |
360 | | STD_PHP_INI_ENTRY("opcache.jit_max_polymorphic_calls" , "2", PHP_INI_ALL, OnUpdateLong, max_polymorphic_calls, zend_jit_globals, jit_globals) |
361 | | STD_PHP_INI_ENTRY("opcache.jit_max_trace_length" , "1024", PHP_INI_ALL, OnUpdateMaxTraceLength, max_trace_length, zend_jit_globals, jit_globals) |
362 | | #endif |
363 | | ZEND_INI_END() |
364 | | |
365 | | static bool filename_is_in_cache(zend_string *filename) |
366 | 0 | { |
367 | 0 | zend_string *key; |
368 | |
|
369 | 0 | key = accel_make_persistent_key(filename); |
370 | 0 | if (key != NULL) { |
371 | 0 | zend_persistent_script *persistent_script = zend_accel_hash_find(&ZCSG(hash), key); |
372 | 0 | if (persistent_script && !persistent_script->corrupted) { |
373 | 0 | if (ZCG(accel_directives).validate_timestamps) { |
374 | 0 | zend_file_handle handle; |
375 | 0 | bool ret; |
376 | |
|
377 | 0 | zend_stream_init_filename_ex(&handle, filename); |
378 | 0 | ret = validate_timestamp_and_record_ex(persistent_script, &handle) == SUCCESS; |
379 | 0 | zend_destroy_file_handle(&handle); |
380 | 0 | return ret; |
381 | 0 | } |
382 | | |
383 | 0 | return true; |
384 | 0 | } |
385 | 0 | } |
386 | | |
387 | 0 | return false; |
388 | 0 | } |
389 | | |
390 | | static bool filename_is_in_file_cache(zend_string *filename) |
391 | 0 | { |
392 | 0 | zend_string *realpath = zend_resolve_path(filename); |
393 | 0 | if (!realpath) { |
394 | 0 | return false; |
395 | 0 | } |
396 | | |
397 | 0 | zend_file_handle handle; |
398 | 0 | zend_stream_init_filename_ex(&handle, filename); |
399 | 0 | handle.opened_path = realpath; |
400 | |
|
401 | 0 | zend_persistent_script *result = zend_file_cache_script_load_ex(&handle, true); |
402 | 0 | zend_destroy_file_handle(&handle); |
403 | |
|
404 | 0 | return result != NULL; |
405 | 0 | } |
406 | | |
407 | | static bool accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS) |
408 | 0 | { |
409 | 0 | if (ZEND_NUM_ARGS() == 1) { |
410 | 0 | zval *zv = ZEND_CALL_ARG(execute_data , 1); |
411 | |
|
412 | 0 | if (Z_TYPE_P(zv) == IS_STRING && Z_STRLEN_P(zv) != 0) { |
413 | 0 | return filename_is_in_cache(Z_STR_P(zv)); |
414 | 0 | } |
415 | 0 | } |
416 | 0 | return false; |
417 | 0 | } |
418 | | |
419 | | static ZEND_NAMED_FUNCTION(accel_file_exists) |
420 | 0 | { |
421 | 0 | if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) { |
422 | 0 | RETURN_TRUE; |
423 | 0 | } else { |
424 | 0 | orig_file_exists(INTERNAL_FUNCTION_PARAM_PASSTHRU); |
425 | 0 | } |
426 | 0 | } |
427 | | |
428 | | static ZEND_NAMED_FUNCTION(accel_is_file) |
429 | 0 | { |
430 | 0 | if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) { |
431 | 0 | RETURN_TRUE; |
432 | 0 | } else { |
433 | 0 | orig_is_file(INTERNAL_FUNCTION_PARAM_PASSTHRU); |
434 | 0 | } |
435 | 0 | } |
436 | | |
437 | | static ZEND_NAMED_FUNCTION(accel_is_readable) |
438 | 0 | { |
439 | 0 | if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) { |
440 | 0 | RETURN_TRUE; |
441 | 0 | } else { |
442 | 0 | orig_is_readable(INTERNAL_FUNCTION_PARAM_PASSTHRU); |
443 | 0 | } |
444 | 0 | } |
445 | | |
446 | | static ZEND_MINIT_FUNCTION(zend_accelerator) |
447 | 16 | { |
448 | 16 | start_accel_extension(); |
449 | | |
450 | 16 | return SUCCESS; |
451 | 16 | } |
452 | | |
453 | | void zend_accel_register_ini_entries(void) |
454 | 16 | { |
455 | 16 | zend_module_entry *module = zend_hash_str_find_ptr_lc(&module_registry, |
456 | 16 | ACCELERATOR_PRODUCT_NAME, strlen(ACCELERATOR_PRODUCT_NAME)); |
457 | | |
458 | 16 | zend_register_ini_entries_ex(ini_entries, module->module_number, module->type); |
459 | 16 | } |
460 | | |
461 | | void zend_accel_override_file_functions(void) |
462 | 16 | { |
463 | 16 | zend_function *old_function; |
464 | 16 | if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).file_override_enabled) { |
465 | 0 | if (file_cache_only) { |
466 | 0 | zend_accel_error(ACCEL_LOG_WARNING, "file_override_enabled has no effect when file_cache_only is set"); |
467 | 0 | return; |
468 | 0 | } |
469 | | /* override file_exists */ |
470 | 0 | if ((old_function = zend_hash_str_find_ptr(CG(function_table), "file_exists", sizeof("file_exists")-1)) != NULL) { |
471 | 0 | orig_file_exists = old_function->internal_function.handler; |
472 | 0 | old_function->internal_function.handler = accel_file_exists; |
473 | 0 | } |
474 | 0 | if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_file", sizeof("is_file")-1)) != NULL) { |
475 | 0 | orig_is_file = old_function->internal_function.handler; |
476 | 0 | old_function->internal_function.handler = accel_is_file; |
477 | 0 | } |
478 | 0 | if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_readable", sizeof("is_readable")-1)) != NULL) { |
479 | 0 | orig_is_readable = old_function->internal_function.handler; |
480 | 0 | old_function->internal_function.handler = accel_is_readable; |
481 | 0 | } |
482 | 0 | } |
483 | 16 | } |
484 | | |
485 | | static ZEND_MSHUTDOWN_FUNCTION(zend_accelerator) |
486 | 0 | { |
487 | 0 | (void)type; /* keep the compiler happy */ |
488 | |
|
489 | 0 | UNREGISTER_INI_ENTRIES(); |
490 | 0 | accel_shutdown(); |
491 | |
|
492 | 0 | return SUCCESS; |
493 | 0 | } |
494 | | |
495 | | void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS) |
496 | 8 | { |
497 | 8 | php_info_print_table_start(); |
498 | | |
499 | 8 | if (ZCG(accelerator_enabled) || file_cache_only) { |
500 | 8 | php_info_print_table_row(2, "Opcode Caching", "Up and Running"); |
501 | 8 | } else { |
502 | 0 | php_info_print_table_row(2, "Opcode Caching", "Disabled"); |
503 | 0 | } |
504 | 8 | if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).optimization_level) { |
505 | 8 | php_info_print_table_row(2, "Optimization", "Enabled"); |
506 | 8 | } else { |
507 | 0 | php_info_print_table_row(2, "Optimization", "Disabled"); |
508 | 0 | } |
509 | 8 | if (!file_cache_only) { |
510 | 8 | php_info_print_table_row(2, "SHM Cache", "Enabled"); |
511 | 8 | } else { |
512 | 0 | php_info_print_table_row(2, "SHM Cache", "Disabled"); |
513 | 0 | } |
514 | 8 | if (ZCG(accel_directives).file_cache) { |
515 | 0 | php_info_print_table_row(2, "File Cache", "Enabled"); |
516 | 8 | } else { |
517 | 8 | php_info_print_table_row(2, "File Cache", "Disabled"); |
518 | 8 | } |
519 | 8 | #ifdef HAVE_JIT |
520 | 8 | if (JIT_G(enabled)) { |
521 | 0 | if (JIT_G(on)) { |
522 | 0 | php_info_print_table_row(2, "JIT", "On"); |
523 | 0 | } else { |
524 | 0 | php_info_print_table_row(2, "JIT", "Off"); |
525 | 0 | } |
526 | 8 | } else { |
527 | 8 | php_info_print_table_row(2, "JIT", "Disabled"); |
528 | 8 | } |
529 | | #else |
530 | | php_info_print_table_row(2, "JIT", "Not Available"); |
531 | | #endif |
532 | 8 | if (file_cache_only) { |
533 | 0 | if (!accel_startup_ok || zps_api_failure_reason) { |
534 | 0 | php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason); |
535 | 0 | } else { |
536 | 0 | php_info_print_table_row(2, "Startup", "OK"); |
537 | 0 | } |
538 | 0 | } else |
539 | 8 | if (ZCG(enabled)) { |
540 | 8 | if (!accel_startup_ok || zps_api_failure_reason) { |
541 | 0 | php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason); |
542 | 8 | } else { |
543 | 8 | char buf[32]; |
544 | 8 | zend_string *start_time, *restart_time, *force_restart_time; |
545 | 8 | zval *date_ISO8601 = zend_get_constant_str("DATE_ISO8601", sizeof("DATE_ISO8601")-1); |
546 | | |
547 | 8 | php_info_print_table_row(2, "Startup", "OK"); |
548 | 8 | php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model()); |
549 | 8 | snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hits)); |
550 | 8 | php_info_print_table_row(2, "Cache hits", buf); |
551 | 8 | snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses)); |
552 | 8 | php_info_print_table_row(2, "Cache misses", buf); |
553 | 8 | snprintf(buf, sizeof(buf), ZEND_LONG_FMT, ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory)); |
554 | 8 | php_info_print_table_row(2, "Used memory", buf); |
555 | 8 | snprintf(buf, sizeof(buf), "%zu", zend_shared_alloc_get_free_memory()); |
556 | 8 | php_info_print_table_row(2, "Free memory", buf); |
557 | 8 | snprintf(buf, sizeof(buf), "%zu", ZSMMG(wasted_shared_memory)); |
558 | 8 | php_info_print_table_row(2, "Wasted memory", buf); |
559 | 8 | if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) { |
560 | 8 | snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).top - (char*)(accel_shared_globals + 1))); |
561 | 8 | php_info_print_table_row(2, "Interned Strings Used memory", buf); |
562 | 8 | snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top)); |
563 | 8 | php_info_print_table_row(2, "Interned Strings Free memory", buf); |
564 | 8 | } |
565 | 8 | snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_direct_entries); |
566 | 8 | php_info_print_table_row(2, "Cached scripts", buf); |
567 | 8 | snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_entries); |
568 | 8 | php_info_print_table_row(2, "Cached keys", buf); |
569 | 8 | snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).max_num_entries); |
570 | 8 | php_info_print_table_row(2, "Max keys", buf); |
571 | 8 | snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(oom_restarts)); |
572 | 8 | php_info_print_table_row(2, "OOM restarts", buf); |
573 | 8 | snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hash_restarts)); |
574 | 8 | php_info_print_table_row(2, "Hash keys restarts", buf); |
575 | 8 | snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(manual_restarts)); |
576 | 8 | php_info_print_table_row(2, "Manual restarts", buf); |
577 | | |
578 | 8 | start_time = php_format_date(Z_STRVAL_P(date_ISO8601), Z_STRLEN_P(date_ISO8601), ZCSG(start_time), 1); |
579 | 8 | php_info_print_table_row(2, "Start time", ZSTR_VAL(start_time)); |
580 | 8 | zend_string_release(start_time); |
581 | | |
582 | 8 | if (ZCSG(last_restart_time)) { |
583 | 0 | restart_time = php_format_date(Z_STRVAL_P(date_ISO8601), Z_STRLEN_P(date_ISO8601), ZCSG(last_restart_time), 1); |
584 | 0 | php_info_print_table_row(2, "Last restart time", ZSTR_VAL(restart_time)); |
585 | 0 | zend_string_release(restart_time); |
586 | 8 | } else { |
587 | 8 | php_info_print_table_row(2, "Last restart time", "none"); |
588 | 8 | } |
589 | | |
590 | 8 | if (ZCSG(force_restart_time)) { |
591 | 0 | force_restart_time = php_format_date(Z_STRVAL_P(date_ISO8601), Z_STRLEN_P(date_ISO8601), ZCSG(force_restart_time), 1); |
592 | 0 | php_info_print_table_row(2, "Last force restart time", ZSTR_VAL(force_restart_time)); |
593 | 0 | zend_string_release(force_restart_time); |
594 | 8 | } else { |
595 | 8 | php_info_print_table_row(2, "Last force restart time", "none"); |
596 | 8 | } |
597 | 8 | } |
598 | 8 | } |
599 | | |
600 | 8 | php_info_print_table_end(); |
601 | 8 | DISPLAY_INI_ENTRIES(); |
602 | 8 | } |
603 | | |
604 | | zend_module_entry opcache_module_entry = { |
605 | | STANDARD_MODULE_HEADER, |
606 | | ACCELERATOR_PRODUCT_NAME, |
607 | | ext_functions, |
608 | | ZEND_MINIT(zend_accelerator), |
609 | | ZEND_MSHUTDOWN(zend_accelerator), |
610 | | ZEND_RINIT(zend_accelerator), |
611 | | NULL, |
612 | | zend_accel_info, |
613 | | PHP_VERSION, |
614 | | NO_MODULE_GLOBALS, |
615 | | accel_post_deactivate, |
616 | | STANDARD_MODULE_PROPERTIES_EX |
617 | | }; |
618 | | |
619 | | /* {{{ Get the scripts which are accelerated by ZendAccelerator */ |
620 | | static int accelerator_get_scripts(zval *return_value) |
621 | 15 | { |
622 | 15 | uint32_t i; |
623 | 15 | zval persistent_script_report; |
624 | 15 | zend_accel_hash_entry *cache_entry; |
625 | 15 | struct tm *ta; |
626 | | |
627 | 15 | if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) { |
628 | 0 | return 0; |
629 | 0 | } |
630 | | |
631 | 15 | array_init(return_value); |
632 | 243k | for (i = 0; i<ZCSG(hash).max_num_entries; i++) { |
633 | 243k | for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) { |
634 | 15 | zend_persistent_script *script; |
635 | 15 | char *str; |
636 | 15 | size_t len; |
637 | | |
638 | 15 | if (cache_entry->indirect) continue; |
639 | | |
640 | 15 | script = (zend_persistent_script *)cache_entry->data; |
641 | | |
642 | 15 | array_init(&persistent_script_report); |
643 | 15 | add_assoc_str(&persistent_script_report, "full_path", zend_string_dup(script->script.filename, 0)); |
644 | 15 | add_assoc_long(&persistent_script_report, "hits", script->dynamic_members.hits); |
645 | 15 | add_assoc_long(&persistent_script_report, "memory_consumption", script->dynamic_members.memory_consumption); |
646 | 15 | ta = localtime(&script->dynamic_members.last_used); |
647 | 15 | str = asctime(ta); |
648 | 15 | len = strlen(str); |
649 | 15 | if (len > 0 && str[len - 1] == '\n') len--; |
650 | 15 | add_assoc_stringl(&persistent_script_report, "last_used", str, len); |
651 | 15 | add_assoc_long(&persistent_script_report, "last_used_timestamp", script->dynamic_members.last_used); |
652 | 15 | if (ZCG(accel_directives).validate_timestamps) { |
653 | 0 | add_assoc_long(&persistent_script_report, "timestamp", (zend_long)script->timestamp); |
654 | 0 | } |
655 | | |
656 | 15 | add_assoc_long(&persistent_script_report, "revalidate", (zend_long)script->dynamic_members.revalidate); |
657 | | |
658 | 15 | zend_hash_update(Z_ARRVAL_P(return_value), cache_entry->key, &persistent_script_report); |
659 | 15 | } |
660 | 243k | } |
661 | 15 | accelerator_shm_read_unlock(); |
662 | | |
663 | 15 | return 1; |
664 | 15 | } |
665 | | |
666 | | /* {{{ Obtain statistics information regarding code acceleration */ |
667 | | ZEND_FUNCTION(opcache_get_status) |
668 | 15 | { |
669 | 15 | zend_long reqs; |
670 | 15 | zval memory_usage, statistics, scripts; |
671 | 15 | bool fetch_scripts = true; |
672 | | |
673 | 15 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &fetch_scripts) == FAILURE) { |
674 | 0 | RETURN_THROWS(); |
675 | 0 | } |
676 | | |
677 | 15 | if (!validate_api_restriction()) { |
678 | 0 | RETURN_FALSE; |
679 | 0 | } |
680 | | |
681 | 15 | if (!accel_startup_ok) { |
682 | 0 | RETURN_FALSE; |
683 | 0 | } |
684 | | |
685 | 15 | array_init(return_value); |
686 | | |
687 | | /* Trivia */ |
688 | 15 | add_assoc_bool(return_value, "opcache_enabled", ZCG(accelerator_enabled)); |
689 | | |
690 | 15 | if (ZCG(accel_directives).file_cache) { |
691 | 0 | add_assoc_string(return_value, "file_cache", ZCG(accel_directives).file_cache); |
692 | 0 | } |
693 | 15 | if (file_cache_only) { |
694 | 0 | add_assoc_bool(return_value, "file_cache_only", 1); |
695 | 0 | return; |
696 | 0 | } |
697 | | |
698 | 15 | add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted)); |
699 | 15 | add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending)); |
700 | 15 | add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress)); |
701 | | |
702 | | /* Memory usage statistics */ |
703 | 15 | array_init(&memory_usage); |
704 | 15 | add_assoc_long(&memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory)); |
705 | 15 | add_assoc_long(&memory_usage, "free_memory", zend_shared_alloc_get_free_memory()); |
706 | 15 | add_assoc_long(&memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory)); |
707 | 15 | add_assoc_double(&memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0); |
708 | 15 | add_assoc_zval(return_value, "memory_usage", &memory_usage); |
709 | | |
710 | 15 | if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) { |
711 | 15 | zval interned_strings_usage; |
712 | | |
713 | 15 | array_init(&interned_strings_usage); |
714 | 15 | add_assoc_long(&interned_strings_usage, "buffer_size", (char*)ZCSG(interned_strings).end - (char*)(accel_shared_globals + 1)); |
715 | 15 | add_assoc_long(&interned_strings_usage, "used_memory", (char*)ZCSG(interned_strings).top - (char*)(accel_shared_globals + 1)); |
716 | 15 | add_assoc_long(&interned_strings_usage, "free_memory", (char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top); |
717 | 15 | add_assoc_long(&interned_strings_usage, "number_of_strings", ZCSG(interned_strings).nNumOfElements); |
718 | 15 | add_assoc_zval(return_value, "interned_strings_usage", &interned_strings_usage); |
719 | 15 | } |
720 | | |
721 | | /* Accelerator statistics */ |
722 | 15 | array_init(&statistics); |
723 | 15 | add_assoc_long(&statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries); |
724 | 15 | add_assoc_long(&statistics, "num_cached_keys", ZCSG(hash).num_entries); |
725 | 15 | add_assoc_long(&statistics, "max_cached_keys", ZCSG(hash).max_num_entries); |
726 | 15 | add_assoc_long(&statistics, "hits", (zend_long)ZCSG(hits)); |
727 | 15 | add_assoc_long(&statistics, "start_time", ZCSG(start_time)); |
728 | 15 | add_assoc_long(&statistics, "last_restart_time", ZCSG(last_restart_time)); |
729 | 15 | add_assoc_long(&statistics, "oom_restarts", ZCSG(oom_restarts)); |
730 | 15 | add_assoc_long(&statistics, "hash_restarts", ZCSG(hash_restarts)); |
731 | 15 | add_assoc_long(&statistics, "manual_restarts", ZCSG(manual_restarts)); |
732 | 15 | add_assoc_long(&statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses)); |
733 | 15 | add_assoc_long(&statistics, "blacklist_misses", ZCSG(blacklist_misses)); |
734 | 15 | reqs = ZCSG(hits)+ZCSG(misses); |
735 | 15 | add_assoc_double(&statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0); |
736 | 15 | add_assoc_double(&statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0); |
737 | 15 | add_assoc_zval(return_value, "opcache_statistics", &statistics); |
738 | | |
739 | 15 | if (ZCSG(preload_script)) { |
740 | 0 | array_init(&statistics); |
741 | |
|
742 | 0 | add_assoc_long(&statistics, "memory_consumption", ZCSG(preload_script)->dynamic_members.memory_consumption); |
743 | |
|
744 | 0 | if (zend_hash_num_elements(&ZCSG(preload_script)->script.function_table)) { |
745 | 0 | zend_op_array *op_array; |
746 | |
|
747 | 0 | array_init(&scripts); |
748 | 0 | ZEND_HASH_MAP_FOREACH_PTR(&ZCSG(preload_script)->script.function_table, op_array) { |
749 | 0 | add_next_index_str(&scripts, op_array->function_name); |
750 | 0 | } ZEND_HASH_FOREACH_END(); |
751 | 0 | add_assoc_zval(&statistics, "functions", &scripts); |
752 | 0 | } |
753 | |
|
754 | 0 | if (zend_hash_num_elements(&ZCSG(preload_script)->script.class_table)) { |
755 | 0 | zval *zv; |
756 | 0 | zend_string *key; |
757 | |
|
758 | 0 | array_init(&scripts); |
759 | 0 | ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(&ZCSG(preload_script)->script.class_table, key, zv) { |
760 | 0 | if (Z_TYPE_P(zv) == IS_ALIAS_PTR) { |
761 | 0 | add_next_index_str(&scripts, key); |
762 | 0 | } else { |
763 | 0 | add_next_index_str(&scripts, Z_CE_P(zv)->name); |
764 | 0 | } |
765 | 0 | } ZEND_HASH_FOREACH_END(); |
766 | 0 | add_assoc_zval(&statistics, "classes", &scripts); |
767 | 0 | } |
768 | |
|
769 | 0 | if (ZCSG(saved_scripts)) { |
770 | 0 | zend_persistent_script **p = ZCSG(saved_scripts); |
771 | |
|
772 | 0 | array_init(&scripts); |
773 | 0 | while (*p) { |
774 | 0 | add_next_index_str(&scripts, (*p)->script.filename); |
775 | 0 | p++; |
776 | 0 | } |
777 | 0 | add_assoc_zval(&statistics, "scripts", &scripts); |
778 | 0 | } |
779 | 0 | add_assoc_zval(return_value, "preload_statistics", &statistics); |
780 | 0 | } |
781 | | |
782 | 15 | if (fetch_scripts) { |
783 | | /* accelerated scripts */ |
784 | 15 | if (accelerator_get_scripts(&scripts)) { |
785 | 15 | add_assoc_zval(return_value, "scripts", &scripts); |
786 | 15 | } |
787 | 15 | } |
788 | 15 | #ifdef HAVE_JIT |
789 | 15 | zend_jit_status(return_value); |
790 | 15 | #endif |
791 | 15 | } |
792 | | |
793 | | static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value) |
794 | 0 | { |
795 | 0 | add_next_index_stringl(return_value, p->path, p->path_length); |
796 | 0 | return 0; |
797 | 0 | } |
798 | | |
799 | | /* {{{ Obtain configuration information */ |
800 | | ZEND_FUNCTION(opcache_get_configuration) |
801 | 0 | { |
802 | 0 | zval directives, version, blacklist; |
803 | |
|
804 | 0 | if (zend_parse_parameters_none() == FAILURE) { |
805 | 0 | RETURN_THROWS(); |
806 | 0 | } |
807 | | |
808 | 0 | if (!validate_api_restriction()) { |
809 | 0 | RETURN_FALSE; |
810 | 0 | } |
811 | | |
812 | 0 | array_init(return_value); |
813 | | |
814 | | /* directives */ |
815 | 0 | array_init(&directives); |
816 | 0 | add_assoc_bool(&directives, "opcache.enable", ZCG(enabled)); |
817 | 0 | add_assoc_bool(&directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli); |
818 | 0 | add_assoc_bool(&directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd); |
819 | 0 | add_assoc_bool(&directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps); |
820 | 0 | add_assoc_bool(&directives, "opcache.validate_permission", ZCG(accel_directives).validate_permission); |
821 | 0 | #ifndef ZEND_WIN32 |
822 | 0 | add_assoc_bool(&directives, "opcache.validate_root", ZCG(accel_directives).validate_root); |
823 | 0 | #endif |
824 | 0 | add_assoc_bool(&directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups); |
825 | 0 | add_assoc_bool(&directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path); |
826 | |
|
827 | 0 | add_assoc_long(&directives, "opcache.log_verbosity_level", ZCG(accel_directives).log_verbosity_level); |
828 | 0 | add_assoc_long(&directives, "opcache.memory_consumption", ZCG(accel_directives).memory_consumption); |
829 | 0 | add_assoc_long(&directives, "opcache.interned_strings_buffer",ZCG(accel_directives).interned_strings_buffer); |
830 | 0 | add_assoc_long(&directives, "opcache.max_accelerated_files", ZCG(accel_directives).max_accelerated_files); |
831 | 0 | add_assoc_double(&directives, "opcache.max_wasted_percentage", ZCG(accel_directives).max_wasted_percentage); |
832 | 0 | add_assoc_long(&directives, "opcache.force_restart_timeout", ZCG(accel_directives).force_restart_timeout); |
833 | 0 | add_assoc_long(&directives, "opcache.revalidate_freq", ZCG(accel_directives).revalidate_freq); |
834 | 0 | add_assoc_string(&directives, "opcache.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model)); |
835 | 0 | add_assoc_string(&directives, "opcache.blacklist_filename", STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename)); |
836 | 0 | add_assoc_long(&directives, "opcache.max_file_size", ZCG(accel_directives).max_file_size); |
837 | 0 | add_assoc_string(&directives, "opcache.error_log", STRING_NOT_NULL(ZCG(accel_directives).error_log)); |
838 | |
|
839 | 0 | add_assoc_bool(&directives, "opcache.protect_memory", ZCG(accel_directives).protect_memory); |
840 | 0 | add_assoc_bool(&directives, "opcache.save_comments", ZCG(accel_directives).save_comments); |
841 | 0 | add_assoc_bool(&directives, "opcache.record_warnings", ZCG(accel_directives).record_warnings); |
842 | 0 | add_assoc_bool(&directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled); |
843 | 0 | add_assoc_long(&directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level); |
844 | |
|
845 | 0 | #ifndef ZEND_WIN32 |
846 | 0 | add_assoc_string(&directives, "opcache.lockfile_path", STRING_NOT_NULL(ZCG(accel_directives).lockfile_path)); |
847 | | #else |
848 | | add_assoc_string(&directives, "opcache.mmap_base", STRING_NOT_NULL(ZCG(accel_directives).mmap_base)); |
849 | | #endif |
850 | |
|
851 | 0 | add_assoc_string(&directives, "opcache.file_cache", ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : ""); |
852 | 0 | add_assoc_bool(&directives, "opcache.file_cache_read_only", ZCG(accel_directives).file_cache_read_only); |
853 | 0 | add_assoc_bool(&directives, "opcache.file_cache_only", ZCG(accel_directives).file_cache_only); |
854 | 0 | add_assoc_bool(&directives, "opcache.file_cache_consistency_checks", ZCG(accel_directives).file_cache_consistency_checks); |
855 | | #if ENABLE_FILE_CACHE_FALLBACK |
856 | | add_assoc_bool(&directives, "opcache.file_cache_fallback", ZCG(accel_directives).file_cache_fallback); |
857 | | #endif |
858 | |
|
859 | 0 | add_assoc_long(&directives, "opcache.file_update_protection", ZCG(accel_directives).file_update_protection); |
860 | 0 | add_assoc_long(&directives, "opcache.opt_debug_level", ZCG(accel_directives).opt_debug_level); |
861 | 0 | add_assoc_string(&directives, "opcache.restrict_api", STRING_NOT_NULL(ZCG(accel_directives).restrict_api)); |
862 | 0 | #ifdef HAVE_HUGE_CODE_PAGES |
863 | 0 | add_assoc_bool(&directives, "opcache.huge_code_pages", ZCG(accel_directives).huge_code_pages); |
864 | 0 | #endif |
865 | 0 | add_assoc_string(&directives, "opcache.preload", STRING_NOT_NULL(ZCG(accel_directives).preload)); |
866 | 0 | #ifndef ZEND_WIN32 |
867 | 0 | add_assoc_string(&directives, "opcache.preload_user", STRING_NOT_NULL(ZCG(accel_directives).preload_user)); |
868 | 0 | #endif |
869 | | #ifdef ZEND_WIN32 |
870 | | add_assoc_string(&directives, "opcache.cache_id", STRING_NOT_NULL(ZCG(accel_directives).cache_id)); |
871 | | #endif |
872 | 0 | #ifdef HAVE_JIT |
873 | 0 | add_assoc_string(&directives, "opcache.jit", JIT_G(options)); |
874 | 0 | add_assoc_long(&directives, "opcache.jit_buffer_size", JIT_G(buffer_size)); |
875 | 0 | add_assoc_long(&directives, "opcache.jit_debug", JIT_G(debug)); |
876 | 0 | add_assoc_long(&directives, "opcache.jit_bisect_limit", JIT_G(bisect_limit)); |
877 | 0 | add_assoc_long(&directives, "opcache.jit_blacklist_root_trace", JIT_G(blacklist_root_trace)); |
878 | 0 | add_assoc_long(&directives, "opcache.jit_blacklist_side_trace", JIT_G(blacklist_side_trace)); |
879 | 0 | add_assoc_long(&directives, "opcache.jit_hot_func", JIT_G(hot_func)); |
880 | 0 | add_assoc_long(&directives, "opcache.jit_hot_loop", JIT_G(hot_loop)); |
881 | 0 | add_assoc_long(&directives, "opcache.jit_hot_return", JIT_G(hot_return)); |
882 | 0 | add_assoc_long(&directives, "opcache.jit_hot_side_exit", JIT_G(hot_side_exit)); |
883 | 0 | add_assoc_long(&directives, "opcache.jit_max_exit_counters", JIT_G(max_exit_counters)); |
884 | 0 | add_assoc_long(&directives, "opcache.jit_max_loop_unrolls", JIT_G(max_loop_unrolls)); |
885 | 0 | add_assoc_long(&directives, "opcache.jit_max_polymorphic_calls", JIT_G(max_polymorphic_calls)); |
886 | 0 | add_assoc_long(&directives, "opcache.jit_max_recursive_calls", JIT_G(max_recursive_calls)); |
887 | 0 | add_assoc_long(&directives, "opcache.jit_max_recursive_returns", JIT_G(max_recursive_returns)); |
888 | 0 | add_assoc_long(&directives, "opcache.jit_max_root_traces", JIT_G(max_root_traces)); |
889 | 0 | add_assoc_long(&directives, "opcache.jit_max_side_traces", JIT_G(max_side_traces)); |
890 | 0 | add_assoc_double(&directives, "opcache.jit_prof_threshold", JIT_G(prof_threshold)); |
891 | 0 | add_assoc_long(&directives, "opcache.jit_max_trace_length", JIT_G(max_trace_length)); |
892 | 0 | #endif |
893 | |
|
894 | 0 | add_assoc_zval(return_value, "directives", &directives); |
895 | | |
896 | | /*version */ |
897 | 0 | array_init(&version); |
898 | 0 | add_assoc_string(&version, "version", PHP_VERSION); |
899 | 0 | add_assoc_string(&version, "opcache_product_name", ACCELERATOR_PRODUCT_NAME); |
900 | 0 | add_assoc_zval(return_value, "version", &version); |
901 | | |
902 | | /* blacklist */ |
903 | 0 | array_init(&blacklist); |
904 | 0 | zend_accel_blacklist_apply(&accel_blacklist, add_blacklist_path, &blacklist); |
905 | 0 | add_assoc_zval(return_value, "blacklist", &blacklist); |
906 | 0 | } |
907 | | |
908 | | /* {{{ Request that the contents of the opcode cache to be reset */ |
909 | | ZEND_FUNCTION(opcache_reset) |
910 | 0 | { |
911 | 0 | if (zend_parse_parameters_none() == FAILURE) { |
912 | 0 | RETURN_THROWS(); |
913 | 0 | } |
914 | | |
915 | 0 | if (!validate_api_restriction()) { |
916 | 0 | RETURN_FALSE; |
917 | 0 | } |
918 | | |
919 | 0 | if ((!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) |
920 | | #if ENABLE_FILE_CACHE_FALLBACK |
921 | | && !fallback_process |
922 | | #endif |
923 | 0 | ) { |
924 | 0 | RETURN_FALSE; |
925 | 0 | } |
926 | | |
927 | | /* exclusive lock */ |
928 | 0 | zend_shared_alloc_lock(); |
929 | 0 | zend_accel_schedule_restart(ACCEL_RESTART_USER); |
930 | 0 | zend_shared_alloc_unlock(); |
931 | 0 | RETURN_TRUE; |
932 | 0 | } |
933 | | |
934 | | /* {{{ Invalidates cached script (in necessary or forced) */ |
935 | | ZEND_FUNCTION(opcache_invalidate) |
936 | 70.8k | { |
937 | 70.8k | zend_string *script_name; |
938 | 70.8k | bool force = false; |
939 | | |
940 | 70.8k | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &script_name, &force) == FAILURE) { |
941 | 0 | RETURN_THROWS(); |
942 | 0 | } |
943 | | |
944 | 70.8k | if (!validate_api_restriction()) { |
945 | 0 | RETURN_FALSE; |
946 | 0 | } |
947 | | |
948 | 70.8k | RETURN_BOOL(zend_accel_invalidate(script_name, force) == SUCCESS); |
949 | 70.8k | } |
950 | | |
951 | | /* {{{ Prevents JIT on function. Call it before the first invocation of the given function. */ |
952 | | ZEND_FUNCTION(opcache_jit_blacklist) |
953 | 11 | { |
954 | 11 | zval *closure; |
955 | | |
956 | 11 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == FAILURE) { |
957 | 0 | RETURN_THROWS(); |
958 | 0 | } |
959 | | |
960 | 11 | #ifdef HAVE_JIT |
961 | 11 | const zend_function *func = zend_get_closure_method_def(Z_OBJ_P(closure)); |
962 | 11 | if (ZEND_USER_CODE(func->type)) { |
963 | 11 | zend_jit_blacklist_function((zend_op_array *)&func->op_array); |
964 | 11 | } |
965 | 11 | #endif |
966 | 11 | } |
967 | | |
968 | | ZEND_FUNCTION(opcache_compile_file) |
969 | 0 | { |
970 | 0 | zend_string *script_name; |
971 | 0 | zend_file_handle handle; |
972 | 0 | zend_op_array *op_array = NULL; |
973 | 0 | zend_execute_data *orig_execute_data = NULL; |
974 | 0 | uint32_t orig_compiler_options; |
975 | |
|
976 | 0 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &script_name) == FAILURE) { |
977 | 0 | RETURN_THROWS(); |
978 | 0 | } |
979 | | |
980 | 0 | if (!accel_startup_ok) { |
981 | 0 | zend_error(E_NOTICE, ACCELERATOR_PRODUCT_NAME " has not been properly started, can't compile file"); |
982 | 0 | RETURN_FALSE; |
983 | 0 | } |
984 | | |
985 | 0 | zend_stream_init_filename_ex(&handle, script_name); |
986 | |
|
987 | 0 | orig_execute_data = EG(current_execute_data); |
988 | 0 | orig_compiler_options = CG(compiler_options); |
989 | 0 | CG(compiler_options) |= ZEND_COMPILE_WITHOUT_EXECUTION; |
990 | |
|
991 | 0 | if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) { |
992 | | /* During preloading, a failure in opcache_compile_file() should result in an overall |
993 | | * preloading failure. Otherwise we may include partially compiled files in the preload |
994 | | * state. */ |
995 | 0 | op_array = persistent_compile_file(&handle, ZEND_INCLUDE); |
996 | 0 | } else { |
997 | 0 | zend_try { |
998 | 0 | op_array = persistent_compile_file(&handle, ZEND_INCLUDE); |
999 | 0 | } zend_catch { |
1000 | 0 | EG(current_execute_data) = orig_execute_data; |
1001 | 0 | zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " could not compile file %s", ZSTR_VAL(handle.filename)); |
1002 | 0 | } zend_end_try(); |
1003 | 0 | } |
1004 | |
|
1005 | 0 | CG(compiler_options) = orig_compiler_options; |
1006 | |
|
1007 | 0 | if(op_array != NULL) { |
1008 | 0 | destroy_op_array(op_array); |
1009 | 0 | efree(op_array); |
1010 | 0 | RETVAL_TRUE; |
1011 | 0 | } else { |
1012 | 0 | RETVAL_FALSE; |
1013 | 0 | } |
1014 | 0 | zend_destroy_file_handle(&handle); |
1015 | 0 | } |
1016 | | |
1017 | | /* {{{ Return true if the script is cached in OPCache, false if it is not cached or if OPCache is not running. */ |
1018 | | ZEND_FUNCTION(opcache_is_script_cached) |
1019 | 0 | { |
1020 | 0 | zend_string *script_name; |
1021 | |
|
1022 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
1023 | 0 | Z_PARAM_STR(script_name) |
1024 | 0 | ZEND_PARSE_PARAMETERS_END(); |
1025 | | |
1026 | 0 | if (!validate_api_restriction()) { |
1027 | 0 | RETURN_FALSE; |
1028 | 0 | } |
1029 | | |
1030 | 0 | if (!ZCG(accelerator_enabled)) { |
1031 | 0 | RETURN_FALSE; |
1032 | 0 | } |
1033 | | |
1034 | 0 | RETURN_BOOL(filename_is_in_cache(script_name)); |
1035 | 0 | } |
1036 | | |
1037 | | /* {{{ Return true if the script is cached in OPCache file cache, false if it is not cached or if OPCache is not running. */ |
1038 | | ZEND_FUNCTION(opcache_is_script_cached_in_file_cache) |
1039 | 0 | { |
1040 | 0 | zend_string *script_name; |
1041 | |
|
1042 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
1043 | 0 | Z_PARAM_STR(script_name) |
1044 | 0 | ZEND_PARSE_PARAMETERS_END(); |
1045 | | |
1046 | 0 | if (!validate_api_restriction()) { |
1047 | 0 | RETURN_FALSE; |
1048 | 0 | } |
1049 | | |
1050 | 0 | if (!(ZCG(accelerator_enabled) || ZCG(accel_directives).file_cache_only)) { |
1051 | 0 | RETURN_FALSE; |
1052 | 0 | } |
1053 | | |
1054 | 0 | if (!ZCG(accel_directives).file_cache) { |
1055 | 0 | RETURN_FALSE; |
1056 | 0 | } |
1057 | | |
1058 | 0 | RETURN_BOOL(filename_is_in_file_cache(script_name)); |
1059 | 0 | } |