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