22#if defined(__linux__) && defined(HAVE_MEMFD_CREATE)
37# include <sys/types.h>
47#define SEM_FILENAME_PREFIX ".ZendSem."
48#define S_H(s) g_shared_alloc_handler->s
54static const char *g_shared_model;
60static MUTEX_T zts_lock;
68 {
"mmap", &zend_alloc_mmap_handlers },
71 {
"shm", &zend_alloc_shm_handlers },
74 {
"posix", &zend_alloc_posix_handlers },
88 zts_lock = tsrm_mutex_alloc();
91#if defined(__linux__) && defined(HAVE_MEMFD_CREATE)
98 lock_file = memfd_create(
"opcache_lock", MFD_CLOEXEC);
128static void no_memory_bailout(
size_t allocate_size,
const char *
error)
133static void copy_shared_segments(
void *to,
void *from,
int count,
int size)
136 void *shared_segments_to_p = ((
char *)to +
count*(
sizeof(
void *)));
137 void *shared_segments_from_p = from;
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);
151 g_shared_alloc_handler = he->
handler;
152 g_shared_model = he->
name;
154 ZSMMG(shared_segments_count) = 0;
156 res =
S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in);
162 if (*shared_segments_p) {
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]);
170 free(*shared_segments_p);
171 *shared_segments_p =
NULL;
173 g_shared_alloc_handler =
NULL;
180 size_t shared_segments_array_size;
182 const char *error_in =
NULL;
191 ZSMMG(shared_free) = requested_size - reserved_size;
199 if (
ZCG(accel_directives).memory_model &&
ZCG(accel_directives).memory_model[0]) {
200 const char *model =
ZCG(accel_directives).memory_model;
202 if (
strncmp(
ZCG(accel_directives).memory_model,
"cgi",
sizeof(
"cgi")) == 0) {
206 for (he = handler_table; he->
name; he++) {
208 res = zend_shared_alloc_try(he, requested_size, &
ZSMMG(shared_segments), &
ZSMMG(shared_segments_count), &error_in);
221#if ENABLE_FILE_CACHE_FALLBACK
228 if (!g_shared_alloc_handler) {
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);
239 if (!g_shared_alloc_handler) {
240 no_memory_bailout(requested_size, error_in);
247#if ENABLE_FILE_CACHE_FALLBACK
254 for (i = 0; i <
ZSMMG(shared_segments_count); i++) {
255 ZSMMG(shared_segments)[i]->end =
ZSMMG(shared_segments)[i]->size;
258 shared_segments_array_size =
ZSMMG(shared_segments_count) *
S_H(segment_type_size)();
264 if (!p_tmp_shared_globals) {
270 tmp_shared_segments =
zend_shared_alloc(shared_segments_array_size +
ZSMMG(shared_segments_count) *
sizeof(
void *));
271 if (!tmp_shared_segments) {
276 copy_shared_segments(tmp_shared_segments,
ZSMMG(shared_segments)[0],
ZSMMG(shared_segments_count),
S_H(segment_type_size)());
278 *p_tmp_shared_globals = tmp_shared_globals;
281 free(
ZSMMG(shared_segments));
282 ZSMMG(shared_segments) = tmp_shared_segments;
285 if (!
ZSMMG(shared_memory_state).positions) {
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;
311 size_t shared_segments_array_size;
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);
321 tmp_shared_segments = shared_segments_buf;
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;
326 for (i = 0; i <
ZSMMG(shared_segments_count); i++) {
327 S_H(detach_segment)(
ZSMMG(shared_segments)[i]);
329 if (shared_segments_array_size > 16) {
330 free(
ZSMMG(shared_segments));
333 g_shared_alloc_handler =
NULL;
338 tsrm_mutex_free(zts_lock);
343static size_t zend_shared_alloc_get_largest_free_block(
void)
346 size_t largest_block_size = 0;
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;
351 if (block_size>largest_block_size) {
352 largest_block_size = block_size;
355 return largest_block_size;
358#define MIN_FREE_MEMORY 64*1024
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; \
374 ZEND_ASSERT(0 &&
"Shared memory lock not obtained");
378 if (block_size >
ZSMMG(shared_free)) {
382 for (i = 0; i <
ZSMMG(shared_segments_count); i++) {
383 if (
ZSMMG(shared_segments)[i]->
end -
ZSMMG(shared_segments)[i]->
pos >= block_size) {
384 void *
retval = (
void *) (((
char *)
ZSMMG(shared_segments)[i]->
p) +
ZSMMG(shared_segments)[i]->
pos);
386 ZSMMG(shared_segments)[i]->pos += block_size;
387 ZSMMG(shared_free) -= block_size;
398 return (
key >> 3) | (
key << ((
sizeof(
key) * 8) - 3));
407 if ((old_p = zend_hash_index_find_ptr(&
ZCG(xlat_table),
key)) !=
NULL) {
411 zend_hash_index_add_new_ptr(&
ZCG(xlat_table),
key, source);
415static zend_always_inline void *_zend_shared_memdup(
void *source,
size_t size,
bool get_xlat,
bool set_xlat,
bool free_source)
423 if ((old_p = zend_hash_index_find_ptr(&
ZCG(xlat_table),
key)) !=
NULL) {
436 zend_hash_index_add_new_ptr(&
ZCG(xlat_table),
key,
retval);
446 return _zend_shared_memdup(source,
size,
true,
true,
true);
451 return _zend_shared_memdup(source,
size,
false,
true,
true);
456 return _zend_shared_memdup(source,
size,
false,
false,
true);
461 return _zend_shared_memdup(source,
size,
true,
true,
false);
466 return _zend_shared_memdup(source,
size,
false,
true,
false);
471 return _zend_shared_memdup(source,
size,
false,
false,
false);
486 struct flock mem_write_lock;
488 mem_write_lock.l_type = F_WRLCK;
490 mem_write_lock.l_start = 0;
491 mem_write_lock.l_len = 1;
494 tsrm_mutex_lock(zts_lock);
499 if (mem_write_lock.l_pid == -1) {
500 mem_write_lock.l_pid = getpid();
505 if (fcntl(
lock_file, F_SETLKW, &mem_write_lock) == -1) {
506 if (
errno == EINTR) {
525 struct flock mem_write_unlock;
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;
536 if (fcntl(
lock_file, F_SETLK, &mem_write_unlock) == -1) {
540 tsrm_mutex_unlock(zts_lock);
566 return ZCG(xlat_table).nNumUsed;
579 zend_hash_index_add_new_ptr(&
ZCG(xlat_table),
key, (
void*)
value);
596 return ZSMMG(shared_free);
603 for (i = 0; i <
ZSMMG(shared_segments_count); i++) {
604 ZSMMG(shared_memory_state).positions[i] =
ZSMMG(shared_segments)[i]->pos;
606 ZSMMG(shared_memory_state).shared_free =
ZSMMG(shared_free);
613 for (i = 0; i <
ZSMMG(shared_segments_count); i++) {
614 ZSMMG(shared_segments)[i]->pos =
ZSMMG(shared_memory_state).positions[i];
616 ZSMMG(shared_free) =
ZSMMG(shared_memory_state).shared_free;
617 ZSMMG(memory_exhausted) = 0;
618 ZSMMG(wasted_shared_memory) = 0;
623 return g_shared_model;
637 for (i = 0; i <
ZSMMG(shared_segments_count); i++) {
640#elif defined(ZEND_WIN32)
647 const int mode =
protected ? PAGE_READONLY : PAGE_READWRITE;
649 for (i = 0; i <
ZSMMG(shared_segments_count); i++) {
651 if (!VirtualProtect(
ZSMMG(shared_segments)[i]->
p,
ZSMMG(shared_segments)[i]->
end,
mode, &oldProtect)) {
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) {
unlink(string $filename, $context=null)
count(Countable|array $value, int $mode=COUNT_NORMAL)
flock($stream, int $operation, &$would_block=null)
memset(ptr, 0, type->size)
unsigned const char * end
unsigned const char * pos
unsigned char key[REFLECTION_KEY_LEN]
int mprotect(void *addr, size_t size, int protection)
const zend_shared_memory_handlers zend_alloc_win32_handlers
void zend_shared_alloc_lock_win32(void)
void zend_shared_alloc_unlock_win32(void)
void zend_shared_alloc_create_lock(void)
const zend_shared_memory_handlers * handler
ZEND_NORETURN void zend_accel_error_noreturn(int type, const char *format,...)
strncmp(string $string1, string $string2, int $length)
strcmp(string $string1, string $string2)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
ZEND_API void ZEND_FASTCALL zend_hash_discard(HashTable *ht, uint32_t nNumUsed)
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
#define zend_always_inline
uint32_t zend_shared_alloc_checkpoint_xlat_table(void)
void zend_shared_alloc_save_state(void)
void zend_shared_alloc_lock(void)
const char * zend_accel_get_shared_model(void)
void * zend_shared_memdup_free(void *source, size_t size)
void zend_shared_alloc_shutdown(void)
bool zend_accel_in_shm(void *ptr)
void zend_shared_alloc_init_xlat_table(void)
void * zend_shared_memdup_put_free(void *source, size_t size)
void * zend_shared_alloc_get_xlat_entry(const void *key_pointer)
void zend_shared_alloc_safe_unlock(void)
#define SHARED_ALLOC_FAILED()
void * zend_shared_memdup_put(void *source, size_t size)
void * zend_shared_memdup_get_put_free(void *source, size_t size)
void zend_shared_alloc_unlock(void)
void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint)
void zend_shared_alloc_clear_xlat_table(void)
#define SEM_FILENAME_PREFIX
void zend_accel_shared_protect(bool protected)
void zend_shared_alloc_destroy_xlat_table(void)
size_t zend_shared_alloc_get_free_memory(void)
void zend_shared_alloc_restore_state(void)
int zend_shared_memdup_size(void *source, size_t size)
ZEND_EXT_API zend_smm_shared_globals * smm_shared_globals
void * zend_shared_memdup_get_put(void *source, size_t size)
void zend_shared_alloc_register_xlat_entry(const void *key_pointer, const void *value)
void * zend_shared_alloc(size_t size)
int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size)
void * zend_shared_memdup(void *source, size_t size)
struct _zend_shared_segment zend_shared_segment
struct _handler_entry zend_shared_memory_handler_entry
#define ZEND_ALIGNED_SIZE(size)
#define FAILED_REATTACHED
#define SUCCESSFULLY_REATTACHED
struct _zend_smm_shared_globals zend_smm_shared_globals