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