Coverage Report

Created: 2025-09-27 06:26

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