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