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