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 #if defined(__linux__) && defined(HAVE_MEMFD_CREATE)
23 # ifndef _GNU_SOURCE
24 # define _GNU_SOURCE
25 # endif
26 # include <sys/mman.h>
27 #endif
28
29 #include <errno.h>
30 #include "ZendAccelerator.h"
31 #include "zend_shared_alloc.h"
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
35 #include <fcntl.h>
36 #ifndef ZEND_WIN32
37 # include <sys/types.h>
38 # include <signal.h>
39 # include <sys/stat.h>
40 # include <stdio.h>
41 #endif
42
43 #ifdef HAVE_MPROTECT
44 # include "sys/mman.h"
45 #endif
46
47 #define SEM_FILENAME_PREFIX ".ZendSem."
48 #define S_H(s) g_shared_alloc_handler->s
49
50 /* True globals */
51 /* old/new mapping. We can use true global even for ZTS because its usage
52 is wrapped with exclusive lock anyway */
53 static const zend_shared_memory_handlers *g_shared_alloc_handler = NULL;
54 static const char *g_shared_model;
55 /* pointer to globals allocated in SHM and shared across processes */
56 zend_smm_shared_globals *smm_shared_globals;
57
58 #ifndef ZEND_WIN32
59 #ifdef ZTS
60 static MUTEX_T zts_lock;
61 #endif
62 int lock_file = -1;
63 static char lockfile_name[MAXPATHLEN];
64 #endif
65
66 static const zend_shared_memory_handler_entry handler_table[] = {
67 #ifdef USE_MMAP
68 { "mmap", &zend_alloc_mmap_handlers },
69 #endif
70 #ifdef USE_SHM
71 { "shm", &zend_alloc_shm_handlers },
72 #endif
73 #ifdef USE_SHM_OPEN
74 { "posix", &zend_alloc_posix_handlers },
75 #endif
76 #ifdef ZEND_WIN32
77 { "win32", &zend_alloc_win32_handlers },
78 #endif
79 { NULL, NULL}
80 };
81
82 #ifndef ZEND_WIN32
zend_shared_alloc_create_lock(char * lockfile_path)83 void zend_shared_alloc_create_lock(char *lockfile_path)
84 {
85 int val;
86
87 #ifdef ZTS
88 zts_lock = tsrm_mutex_alloc();
89 #endif
90
91 #if defined(__linux__) && defined(HAVE_MEMFD_CREATE)
92 /* on Linux, we can use a memfd instead of a "real" file, so
93 * we can do this without a writable filesystem and without
94 * needing to clean up */
95 /* note: FreeBSD has memfd_create(), too, but fcntl(F_SETLKW)
96 * on it fails with EBADF, therefore we use this only on
97 * Linux */
98 lock_file = memfd_create("opcache_lock", MFD_CLOEXEC);
99 if (lock_file >= 0)
100 return;
101 #endif
102
103 snprintf(lockfile_name, sizeof(lockfile_name), "%s/%sXXXXXX", lockfile_path, SEM_FILENAME_PREFIX);
104 lock_file = mkstemp(lockfile_name);
105 if (lock_file == -1) {
106 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Unable to create lock file: %s (%d)", strerror(errno), errno);
107 }
108
109 fchmod(lock_file, 0666);
110
111 val = fcntl(lock_file, F_GETFD, 0);
112 val |= FD_CLOEXEC;
113 fcntl(lock_file, F_SETFD, val);
114
115 unlink(lockfile_name);
116 }
117 #endif
118
no_memory_bailout(size_t allocate_size,const char * error)119 static void no_memory_bailout(size_t allocate_size, const char *error)
120 {
121 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Unable to allocate shared memory segment of %zu bytes: %s: %s (%d)", allocate_size, error?error:"unknown", strerror(errno), errno );
122 }
123
copy_shared_segments(void * to,void * from,int count,int size)124 static void copy_shared_segments(void *to, void *from, int count, int size)
125 {
126 zend_shared_segment **shared_segments_v = (zend_shared_segment **)to;
127 void *shared_segments_to_p = ((char *)to + count*(sizeof(void *)));
128 void *shared_segments_from_p = from;
129 int i;
130
131 for (i = 0; i < count; i++) {
132 shared_segments_v[i] = shared_segments_to_p;
133 memcpy(shared_segments_to_p, shared_segments_from_p, size);
134 shared_segments_to_p = ((char *)shared_segments_to_p + size);
135 shared_segments_from_p = ((char *)shared_segments_from_p + size);
136 }
137 }
138
zend_shared_alloc_try(const zend_shared_memory_handler_entry * he,size_t requested_size,zend_shared_segment *** shared_segments_p,int * shared_segments_count,const char ** error_in)139 static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, const char **error_in)
140 {
141 int res;
142 g_shared_alloc_handler = he->handler;
143 g_shared_model = he->name;
144 ZSMMG(shared_segments) = NULL;
145 ZSMMG(shared_segments_count) = 0;
146
147 res = S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in);
148
149 if (res) {
150 /* this model works! */
151 return res;
152 }
153 if (*shared_segments_p) {
154 int i;
155 /* cleanup */
156 for (i = 0; i < *shared_segments_count; i++) {
157 if ((*shared_segments_p)[i]->p && (*shared_segments_p)[i]->p != (void *)-1) {
158 S_H(detach_segment)((*shared_segments_p)[i]);
159 }
160 }
161 free(*shared_segments_p);
162 *shared_segments_p = NULL;
163 }
164 g_shared_alloc_handler = NULL;
165 return ALLOC_FAILURE;
166 }
167
zend_shared_alloc_startup(size_t requested_size,size_t reserved_size)168 int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size)
169 {
170 zend_shared_segment **tmp_shared_segments;
171 size_t shared_segments_array_size;
172 zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals;
173 const char *error_in = NULL;
174 const zend_shared_memory_handler_entry *he;
175 int res = ALLOC_FAILURE;
176 int i;
177
178 /* shared_free must be valid before we call zend_shared_alloc()
179 * - make it temporarily point to a local variable
180 */
181 smm_shared_globals = &tmp_shared_globals;
182 ZSMMG(shared_free) = requested_size - reserved_size; /* goes to tmp_shared_globals.shared_free */
183
184 #ifndef ZEND_WIN32
185 zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path);
186 #else
187 zend_shared_alloc_create_lock();
188 #endif
189
190 if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) {
191 const char *model = ZCG(accel_directives).memory_model;
192 /* "cgi" is really "shm"... */
193 if (strncmp(ZCG(accel_directives).memory_model, "cgi", sizeof("cgi")) == 0) {
194 model = "shm";
195 }
196
197 for (he = handler_table; he->name; he++) {
198 if (strcmp(model, he->name) == 0) {
199 res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
200 if (res) {
201 /* this model works! */
202 break;
203 }
204 }
205 }
206 }
207
208 if (res == FAILED_REATTACHED) {
209 smm_shared_globals = NULL;
210 return res;
211 }
212 #if ENABLE_FILE_CACHE_FALLBACK
213 if (ALLOC_FALLBACK == res) {
214 smm_shared_globals = NULL;
215 return ALLOC_FALLBACK;
216 }
217 #endif
218
219 if (!g_shared_alloc_handler) {
220 /* try memory handlers in order */
221 for (he = handler_table; he->name; he++) {
222 res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
223 if (res) {
224 /* this model works! */
225 break;
226 }
227 }
228 }
229
230 if (!g_shared_alloc_handler) {
231 no_memory_bailout(requested_size, error_in);
232 return ALLOC_FAILURE;
233 }
234
235 if (res == SUCCESSFULLY_REATTACHED) {
236 return res;
237 }
238 #if ENABLE_FILE_CACHE_FALLBACK
239 if (ALLOC_FALLBACK == res) {
240 smm_shared_globals = NULL;
241 return ALLOC_FALLBACK;
242 }
243 #endif
244
245 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
246 ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size;
247 }
248
249 shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)();
250
251 /* move shared_segments and shared_free to shared memory */
252 ZCG(locked) = 1; /* no need to perform a real lock at this point */
253
254 p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals));
255 if (!p_tmp_shared_globals) {
256 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
257 return ALLOC_FAILURE;
258 }
259 memset(p_tmp_shared_globals, 0, sizeof(zend_smm_shared_globals));
260
261 tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *));
262 if (!tmp_shared_segments) {
263 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
264 return ALLOC_FAILURE;
265 }
266
267 copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
268
269 *p_tmp_shared_globals = tmp_shared_globals;
270 smm_shared_globals = p_tmp_shared_globals;
271
272 free(ZSMMG(shared_segments));
273 ZSMMG(shared_segments) = tmp_shared_segments;
274
275 ZSMMG(shared_memory_state).positions = (size_t *)zend_shared_alloc(sizeof(size_t) * ZSMMG(shared_segments_count));
276 if (!ZSMMG(shared_memory_state).positions) {
277 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
278 return ALLOC_FAILURE;
279 }
280
281 if (reserved_size) {
282 i = ZSMMG(shared_segments_count) - 1;
283 if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= reserved_size) {
284 ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size - reserved_size;
285 ZSMMG(reserved) = (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end;
286 ZSMMG(reserved_size) = reserved_size;
287 } else {
288 zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
289 return ALLOC_FAILURE;
290 }
291 }
292
293 ZCG(locked) = 0;
294
295 return res;
296 }
297
zend_shared_alloc_shutdown(void)298 void zend_shared_alloc_shutdown(void)
299 {
300 zend_shared_segment **tmp_shared_segments;
301 zend_shared_segment *shared_segments_buf[16];
302 size_t shared_segments_array_size;
303 zend_smm_shared_globals tmp_shared_globals;
304 int i;
305
306 tmp_shared_globals = *smm_shared_globals;
307 smm_shared_globals = &tmp_shared_globals;
308 shared_segments_array_size = ZSMMG(shared_segments_count) * (S_H(segment_type_size)() + sizeof(void *));
309 if (shared_segments_array_size > 16) {
310 tmp_shared_segments = malloc(shared_segments_array_size);
311 } else {
312 tmp_shared_segments = shared_segments_buf;
313 }
314 copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
315 ZSMMG(shared_segments) = tmp_shared_segments;
316
317 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
318 S_H(detach_segment)(ZSMMG(shared_segments)[i]);
319 }
320 if (shared_segments_array_size > 16) {
321 free(ZSMMG(shared_segments));
322 }
323 ZSMMG(shared_segments) = NULL;
324 g_shared_alloc_handler = NULL;
325 #ifndef ZEND_WIN32
326 close(lock_file);
327
328 # ifdef ZTS
329 tsrm_mutex_free(zts_lock);
330 # endif
331 #endif
332 }
333
zend_shared_alloc_get_largest_free_block(void)334 static size_t zend_shared_alloc_get_largest_free_block(void)
335 {
336 int i;
337 size_t largest_block_size = 0;
338
339 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
340 size_t block_size = ZSMMG(shared_segments)[i]->end - ZSMMG(shared_segments)[i]->pos;
341
342 if (block_size>largest_block_size) {
343 largest_block_size = block_size;
344 }
345 }
346 return largest_block_size;
347 }
348
349 #define MIN_FREE_MEMORY 64*1024
350
351 #define SHARED_ALLOC_FAILED() do { \
352 zend_accel_error(ACCEL_LOG_WARNING, "Not enough free shared space to allocate %zu bytes (%zu bytes free)", size, ZSMMG(shared_free)); \
353 if (zend_shared_alloc_get_largest_free_block() < MIN_FREE_MEMORY) { \
354 ZSMMG(memory_exhausted) = 1; \
355 } \
356 } while (0)
357
zend_shared_alloc(size_t size)358 void *zend_shared_alloc(size_t size)
359 {
360 int i;
361 unsigned int block_size = ZEND_ALIGNED_SIZE(size);
362
363 if (UNEXPECTED(block_size < size)) {
364 zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Possible integer overflow in shared memory allocation (%zu + %zu)", size, PLATFORM_ALIGNMENT);
365 }
366
367 #if 1
368 if (!ZCG(locked)) {
369 ZEND_ASSERT(0 && "Shared memory lock not obtained");
370 zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Shared memory lock not obtained");
371 }
372 #endif
373 if (block_size > ZSMMG(shared_free)) { /* No hope to find a big-enough block */
374 SHARED_ALLOC_FAILED();
375 return NULL;
376 }
377 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
378 if (ZSMMG(shared_segments)[i]->end - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
379 void *retval = (void *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);
380
381 ZSMMG(shared_segments)[i]->pos += block_size;
382 ZSMMG(shared_free) -= block_size;
383 ZEND_ASSERT(((uintptr_t)retval & 0x7) == 0); /* should be 8 byte aligned */
384 return retval;
385 }
386 }
387 SHARED_ALLOC_FAILED();
388 return NULL;
389 }
390
zend_rotr3(zend_ulong key)391 static zend_always_inline zend_ulong zend_rotr3(zend_ulong key)
392 {
393 return (key >> 3) | (key << ((sizeof(key) * 8) - 3));
394 }
395
zend_shared_memdup_size(void * source,size_t size)396 int zend_shared_memdup_size(void *source, size_t size)
397 {
398 void *old_p;
399 zend_ulong key = (zend_ulong)source;
400
401 key = zend_rotr3(key);
402 if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) != NULL) {
403 /* we already duplicated this pointer */
404 return 0;
405 }
406 zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, source);
407 return ZEND_ALIGNED_SIZE(size);
408 }
409
_zend_shared_memdup(void * source,size_t size,bool get_xlat,bool set_xlat,bool free_source)410 static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, bool get_xlat, bool set_xlat, bool free_source)
411 {
412 void *old_p, *retval;
413 zend_ulong key;
414
415 if (get_xlat) {
416 key = (zend_ulong)source;
417 key = zend_rotr3(key);
418 if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) != NULL) {
419 /* we already duplicated this pointer */
420 return old_p;
421 }
422 }
423 retval = ZCG(mem);
424 ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
425 memcpy(retval, source, size);
426 if (set_xlat) {
427 if (!get_xlat) {
428 key = (zend_ulong)source;
429 key = zend_rotr3(key);
430 }
431 zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, retval);
432 }
433 if (free_source) {
434 efree(source);
435 }
436 return retval;
437 }
438
zend_shared_memdup_get_put_free(void * source,size_t size)439 void *zend_shared_memdup_get_put_free(void *source, size_t size)
440 {
441 return _zend_shared_memdup(source, size, true, true, true);
442 }
443
zend_shared_memdup_put_free(void * source,size_t size)444 void *zend_shared_memdup_put_free(void *source, size_t size)
445 {
446 return _zend_shared_memdup(source, size, false, true, true);
447 }
448
zend_shared_memdup_free(void * source,size_t size)449 void *zend_shared_memdup_free(void *source, size_t size)
450 {
451 return _zend_shared_memdup(source, size, false, false, true);
452 }
453
zend_shared_memdup_get_put(void * source,size_t size)454 void *zend_shared_memdup_get_put(void *source, size_t size)
455 {
456 return _zend_shared_memdup(source, size, true, true, false);
457 }
458
zend_shared_memdup_put(void * source,size_t size)459 void *zend_shared_memdup_put(void *source, size_t size)
460 {
461 return _zend_shared_memdup(source, size, false, true, false);
462 }
463
zend_shared_memdup(void * source,size_t size)464 void *zend_shared_memdup(void *source, size_t size)
465 {
466 return _zend_shared_memdup(source, size, false, false, false);
467 }
468
zend_shared_alloc_safe_unlock(void)469 void zend_shared_alloc_safe_unlock(void)
470 {
471 if (ZCG(locked)) {
472 zend_shared_alloc_unlock();
473 }
474 }
475
zend_shared_alloc_lock(void)476 void zend_shared_alloc_lock(void)
477 {
478 ZEND_ASSERT(!ZCG(locked));
479
480 #ifndef ZEND_WIN32
481 struct flock mem_write_lock;
482
483 mem_write_lock.l_type = F_WRLCK;
484 mem_write_lock.l_whence = SEEK_SET;
485 mem_write_lock.l_start = 0;
486 mem_write_lock.l_len = 1;
487
488 #ifdef ZTS
489 tsrm_mutex_lock(zts_lock);
490 #endif
491
492 #if 0
493 /* this will happen once per process, and will un-globalize mem_write_lock */
494 if (mem_write_lock.l_pid == -1) {
495 mem_write_lock.l_pid = getpid();
496 }
497 #endif
498
499 while (1) {
500 if (fcntl(lock_file, F_SETLKW, &mem_write_lock) == -1) {
501 if (errno == EINTR) {
502 continue;
503 }
504 zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot create lock - %s (%d)", strerror(errno), errno);
505 }
506 break;
507 }
508 #else
509 zend_shared_alloc_lock_win32();
510 #endif
511
512 ZCG(locked) = 1;
513 }
514
zend_shared_alloc_unlock(void)515 void zend_shared_alloc_unlock(void)
516 {
517 ZEND_ASSERT(ZCG(locked));
518
519 #ifndef ZEND_WIN32
520 struct flock mem_write_unlock;
521
522 mem_write_unlock.l_type = F_UNLCK;
523 mem_write_unlock.l_whence = SEEK_SET;
524 mem_write_unlock.l_start = 0;
525 mem_write_unlock.l_len = 1;
526 #endif
527
528 ZCG(locked) = 0;
529
530 #ifndef ZEND_WIN32
531 if (fcntl(lock_file, F_SETLK, &mem_write_unlock) == -1) {
532 zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot remove lock - %s (%d)", strerror(errno), errno);
533 }
534 #ifdef ZTS
535 tsrm_mutex_unlock(zts_lock);
536 #endif
537 #else
538 zend_shared_alloc_unlock_win32();
539 #endif
540 }
541
zend_shared_alloc_init_xlat_table(void)542 void zend_shared_alloc_init_xlat_table(void)
543 {
544 /* Prepare translation table */
545 zend_hash_init(&ZCG(xlat_table), 128, NULL, NULL, 0);
546 }
547
zend_shared_alloc_destroy_xlat_table(void)548 void zend_shared_alloc_destroy_xlat_table(void)
549 {
550 /* Destroy translation table */
551 zend_hash_destroy(&ZCG(xlat_table));
552 }
553
zend_shared_alloc_clear_xlat_table(void)554 void zend_shared_alloc_clear_xlat_table(void)
555 {
556 zend_hash_clean(&ZCG(xlat_table));
557 }
558
zend_shared_alloc_checkpoint_xlat_table(void)559 uint32_t zend_shared_alloc_checkpoint_xlat_table(void)
560 {
561 return ZCG(xlat_table).nNumUsed;
562 }
563
zend_shared_alloc_restore_xlat_table(uint32_t checkpoint)564 void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint)
565 {
566 zend_hash_discard(&ZCG(xlat_table), checkpoint);
567 }
568
zend_shared_alloc_register_xlat_entry(const void * key_pointer,const void * value)569 void zend_shared_alloc_register_xlat_entry(const void *key_pointer, const void *value)
570 {
571 zend_ulong key = (zend_ulong)key_pointer;
572
573 key = zend_rotr3(key);
574 zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, (void*)value);
575 }
576
zend_shared_alloc_get_xlat_entry(const void * key_pointer)577 void *zend_shared_alloc_get_xlat_entry(const void *key_pointer)
578 {
579 void *retval;
580 zend_ulong key = (zend_ulong)key_pointer;
581
582 key = zend_rotr3(key);
583 if ((retval = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) == NULL) {
584 return NULL;
585 }
586 return retval;
587 }
588
zend_shared_alloc_get_free_memory(void)589 size_t zend_shared_alloc_get_free_memory(void)
590 {
591 return ZSMMG(shared_free);
592 }
593
zend_shared_alloc_save_state(void)594 void zend_shared_alloc_save_state(void)
595 {
596 int i;
597
598 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
599 ZSMMG(shared_memory_state).positions[i] = ZSMMG(shared_segments)[i]->pos;
600 }
601 ZSMMG(shared_memory_state).shared_free = ZSMMG(shared_free);
602 }
603
zend_shared_alloc_restore_state(void)604 void zend_shared_alloc_restore_state(void)
605 {
606 int i;
607
608 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
609 ZSMMG(shared_segments)[i]->pos = ZSMMG(shared_memory_state).positions[i];
610 }
611 ZSMMG(shared_free) = ZSMMG(shared_memory_state).shared_free;
612 ZSMMG(memory_exhausted) = 0;
613 ZSMMG(wasted_shared_memory) = 0;
614 }
615
zend_accel_get_shared_model(void)616 const char *zend_accel_get_shared_model(void)
617 {
618 return g_shared_model;
619 }
620
zend_accel_shared_protect(bool protected)621 void zend_accel_shared_protect(bool protected)
622 {
623 #ifdef HAVE_MPROTECT
624 int i;
625
626 if (!smm_shared_globals) {
627 return;
628 }
629
630 const int mode = protected ? PROT_READ : PROT_READ|PROT_WRITE;
631
632 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
633 mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode);
634 }
635 #elif defined(ZEND_WIN32)
636 int i;
637
638 if (!smm_shared_globals) {
639 return;
640 }
641
642 const int mode = protected ? PAGE_READONLY : PAGE_READWRITE;
643
644 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
645 DWORD oldProtect;
646 if (!VirtualProtect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode, &oldProtect)) {
647 zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Failed to protect memory");
648 }
649 }
650 #endif
651 }
652
zend_accel_in_shm(void * ptr)653 bool zend_accel_in_shm(void *ptr)
654 {
655 int i;
656
657 if (!smm_shared_globals) {
658 return false;
659 }
660
661 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
662 if ((char*)ptr >= (char*)ZSMMG(shared_segments)[i]->p &&
663 (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end) {
664 return true;
665 }
666 }
667 return false;
668 }
669