This source file includes following definitions.
- zend_shared_alloc_create_lock
- no_memory_bailout
- copy_shared_segments
- zend_shared_alloc_try
- zend_shared_alloc_startup
- zend_shared_alloc_shutdown
- zend_shared_alloc_get_largest_free_block
- zend_shared_alloc
- zend_shared_memdup_size
- _zend_shared_memdup
- zend_shared_alloc_safe_unlock
- zend_shared_alloc_lock
- zend_shared_alloc_unlock
- zend_shared_alloc_init_xlat_table
- zend_shared_alloc_destroy_xlat_table
- zend_shared_alloc_clear_xlat_table
- zend_shared_alloc_register_xlat_entry
- zend_shared_alloc_get_xlat_entry
- zend_shared_alloc_get_free_memory
- zend_shared_alloc_save_state
- zend_shared_alloc_restore_state
- zend_accel_get_shared_model
- zend_accel_shared_protect
- zend_accel_in_shm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 <dirent.h>
32 # include <signal.h>
33 # include <sys/stat.h>
34 # include <stdio.h>
35 #endif
36
37 #ifdef HAVE_MPROTECT
38 # include "sys/mman.h"
39 #endif
40
41 #define TMP_DIR "/tmp"
42 #define SEM_FILENAME_PREFIX ".ZendSem."
43 #define S_H(s) g_shared_alloc_handler->s
44
45
46
47
48 static const zend_shared_memory_handlers *g_shared_alloc_handler = NULL;
49 static const char *g_shared_model;
50
51 zend_smm_shared_globals *smm_shared_globals;
52
53 #ifndef ZEND_WIN32
54 #ifdef ZTS
55 static MUTEX_T zts_lock;
56 #endif
57 int lock_file;
58 static char lockfile_name[sizeof(TMP_DIR) + sizeof(SEM_FILENAME_PREFIX) + 8];
59 #endif
60
61 static const zend_shared_memory_handler_entry handler_table[] = {
62 #ifdef USE_MMAP
63 { "mmap", &zend_alloc_mmap_handlers },
64 #endif
65 #ifdef USE_SHM
66 { "shm", &zend_alloc_shm_handlers },
67 #endif
68 #ifdef USE_SHM_OPEN
69 { "posix", &zend_alloc_posix_handlers },
70 #endif
71 #ifdef ZEND_WIN32
72 { "win32", &zend_alloc_win32_handlers },
73 #endif
74 { NULL, NULL}
75 };
76
77 #ifndef ZEND_WIN32
78 void zend_shared_alloc_create_lock(void)
79 {
80 int val;
81
82 #ifdef ZTS
83 zts_lock = tsrm_mutex_alloc();
84 #endif
85
86 sprintf(lockfile_name, "%s/%sXXXXXX", TMP_DIR, SEM_FILENAME_PREFIX);
87 lock_file = mkstemp(lockfile_name);
88 fchmod(lock_file, 0666);
89
90 if (lock_file == -1) {
91 zend_accel_error(ACCEL_LOG_FATAL, "Unable to create lock file: %s (%d)", strerror(errno), errno);
92 }
93 val = fcntl(lock_file, F_GETFD, 0);
94 val |= FD_CLOEXEC;
95 fcntl(lock_file, F_SETFD, val);
96
97 unlink(lockfile_name);
98 }
99 #endif
100
101 static void no_memory_bailout(size_t allocate_size, char *error)
102 {
103 zend_accel_error(ACCEL_LOG_FATAL, "Unable to allocate shared memory segment of %ld bytes: %s: %s (%d)", allocate_size, error?error:"unknown", strerror(errno), errno );
104 }
105
106 static void copy_shared_segments(void *to, void *from, int count, int size)
107 {
108 zend_shared_segment **shared_segments_v = (zend_shared_segment **)to;
109 void *shared_segments_to_p = ((char *)to + count*(sizeof(void *)));
110 void *shared_segments_from_p = from;
111 int i;
112
113 for (i = 0; i < count; i++) {
114 shared_segments_v[i] = shared_segments_to_p;
115 memcpy(shared_segments_to_p, shared_segments_from_p, size);
116 shared_segments_to_p = ((char *)shared_segments_to_p + size);
117 shared_segments_from_p = ((char *)shared_segments_from_p + size);
118 }
119 }
120
121 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)
122 {
123 int res;
124 g_shared_alloc_handler = he->handler;
125 g_shared_model = he->name;
126 ZSMMG(shared_segments) = NULL;
127 ZSMMG(shared_segments_count) = 0;
128
129 res = S_H(create_segments)(requested_size, shared_segments_p, shared_segments_count, error_in);
130
131 if (res) {
132
133 return res;
134 }
135 if (*shared_segments_p) {
136 int i;
137
138 for (i = 0; i < *shared_segments_count; i++) {
139 if ((*shared_segments_p)[i]->p && (*shared_segments_p)[i]->p != (void *)-1) {
140 S_H(detach_segment)((*shared_segments_p)[i]);
141 }
142 }
143 free(*shared_segments_p);
144 *shared_segments_p = NULL;
145 }
146 g_shared_alloc_handler = NULL;
147 return ALLOC_FAILURE;
148 }
149
150 int zend_shared_alloc_startup(size_t requested_size)
151 {
152 zend_shared_segment **tmp_shared_segments;
153 size_t shared_segments_array_size;
154 zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals;
155 char *error_in = NULL;
156 const zend_shared_memory_handler_entry *he;
157 int res = ALLOC_FAILURE;
158
159
160
161
162
163 smm_shared_globals = &tmp_shared_globals;
164 ZSMMG(shared_free) = requested_size;
165
166 zend_shared_alloc_create_lock();
167
168 if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) {
169 char *model = ZCG(accel_directives).memory_model;
170
171 if (strncmp(ZCG(accel_directives).memory_model, "cgi", sizeof("cgi")) == 0) {
172 model = "shm";
173 }
174
175 for (he = handler_table; he->name; he++) {
176 if (strcmp(model, he->name) == 0) {
177 res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
178 if (res) {
179
180 }
181 break;
182 }
183 }
184 }
185
186 if (res == FAILED_REATTACHED) {
187 smm_shared_globals = NULL;
188 return res;
189 }
190 #if ENABLE_FILE_CACHE_FALLBACK
191 if (ALLOC_FALLBACK == res) {
192 return ALLOC_FALLBACK;
193 }
194 #endif
195
196 if (!g_shared_alloc_handler) {
197
198 for (he = handler_table; he->name; he++) {
199 res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
200 if (res) {
201
202 break;
203 }
204 }
205 }
206
207 if (!g_shared_alloc_handler) {
208 no_memory_bailout(requested_size, error_in);
209 return ALLOC_FAILURE;
210 }
211
212 if (res == SUCCESSFULLY_REATTACHED) {
213 return res;
214 }
215 #if ENABLE_FILE_CACHE_FALLBACK
216 if (ALLOC_FALLBACK == res) {
217 return ALLOC_FALLBACK;
218 }
219 #endif
220
221 shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)();
222
223
224 ZCG(locked) = 1;
225 p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals));
226 if (!p_tmp_shared_globals) {
227 zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
228 return ALLOC_FAILURE;;
229 }
230
231 tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *));
232 if (!tmp_shared_segments) {
233 zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
234 return ALLOC_FAILURE;;
235 }
236
237 copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
238
239 *p_tmp_shared_globals = tmp_shared_globals;
240 smm_shared_globals = p_tmp_shared_globals;
241
242 free(ZSMMG(shared_segments));
243 ZSMMG(shared_segments) = tmp_shared_segments;
244
245 ZSMMG(shared_memory_state).positions = (int *)zend_shared_alloc(sizeof(int) * ZSMMG(shared_segments_count));
246 if (!ZSMMG(shared_memory_state).positions) {
247 zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
248 return ALLOC_FAILURE;;
249 }
250
251 ZCG(locked) = 0;
252
253 return res;
254 }
255
256 void zend_shared_alloc_shutdown(void)
257 {
258 zend_shared_segment **tmp_shared_segments;
259 size_t shared_segments_array_size;
260 zend_smm_shared_globals tmp_shared_globals;
261 int i;
262
263 tmp_shared_globals = *smm_shared_globals;
264 smm_shared_globals = &tmp_shared_globals;
265 shared_segments_array_size = ZSMMG(shared_segments_count) * (S_H(segment_type_size)() + sizeof(void *));
266 tmp_shared_segments = emalloc(shared_segments_array_size);
267 copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)());
268 ZSMMG(shared_segments) = tmp_shared_segments;
269
270 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
271 S_H(detach_segment)(ZSMMG(shared_segments)[i]);
272 }
273 efree(ZSMMG(shared_segments));
274 ZSMMG(shared_segments) = NULL;
275 g_shared_alloc_handler = NULL;
276 #ifndef ZEND_WIN32
277 close(lock_file);
278 #endif
279 }
280
281 static size_t zend_shared_alloc_get_largest_free_block(void)
282 {
283 int i;
284 size_t largest_block_size = 0;
285
286 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
287 size_t block_size = ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos;
288
289 if (block_size>largest_block_size) {
290 largest_block_size = block_size;
291 }
292 }
293 return largest_block_size;
294 }
295
296 #define MIN_FREE_MEMORY 64*1024
297
298 #define SHARED_ALLOC_FAILED() do { \
299 zend_accel_error(ACCEL_LOG_WARNING, "Not enough free shared space to allocate %pd bytes (%pd bytes free)", (zend_long)size, (zend_long)ZSMMG(shared_free)); \
300 if (zend_shared_alloc_get_largest_free_block() < MIN_FREE_MEMORY) { \
301 ZSMMG(memory_exhausted) = 1; \
302 } \
303 } while (0)
304
305 void *zend_shared_alloc(size_t size)
306 {
307 int i;
308 unsigned int block_size = ZEND_ALIGNED_SIZE(size);
309
310 #if 1
311 if (!ZCG(locked)) {
312 zend_accel_error(ACCEL_LOG_ERROR, "Shared memory lock not obtained");
313 }
314 #endif
315 if (block_size > ZSMMG(shared_free)) {
316 SHARED_ALLOC_FAILED();
317 return NULL;
318 }
319 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
320 if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= block_size) {
321 void *retval = (void *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);
322
323 ZSMMG(shared_segments)[i]->pos += block_size;
324 ZSMMG(shared_free) -= block_size;
325 memset(retval, 0, block_size);
326 ZEND_ASSERT(((zend_uintptr_t)retval & 0x7) == 0);
327 return retval;
328 }
329 }
330 SHARED_ALLOC_FAILED();
331 return NULL;
332 }
333
334 int zend_shared_memdup_size(void *source, size_t size)
335 {
336 void *old_p;
337
338 if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)source)) != NULL) {
339
340 return 0;
341 }
342 zend_shared_alloc_register_xlat_entry(source, source);
343 return ZEND_ALIGNED_SIZE(size);
344 }
345
346 void *_zend_shared_memdup(void *source, size_t size, zend_bool free_source)
347 {
348 void *old_p, *retval;
349
350 if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)source)) != NULL) {
351
352 return old_p;
353 }
354 retval = ZCG(mem);
355 ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
356 memcpy(retval, source, size);
357 zend_shared_alloc_register_xlat_entry(source, retval);
358 if (free_source) {
359 efree(source);
360 }
361 return retval;
362 }
363
364 void zend_shared_alloc_safe_unlock(void)
365 {
366 if (ZCG(locked)) {
367 zend_shared_alloc_unlock();
368 }
369 }
370
371 #ifndef ZEND_WIN32
372
373 static FLOCK_STRUCTURE(mem_write_lock, F_WRLCK, SEEK_SET, 0, 1);
374 static FLOCK_STRUCTURE(mem_write_unlock, F_UNLCK, SEEK_SET, 0, 1);
375 #endif
376
377 void zend_shared_alloc_lock(void)
378 {
379 #ifndef ZEND_WIN32
380
381 #ifdef ZTS
382 tsrm_mutex_lock(zts_lock);
383 #endif
384
385 #if 0
386
387 if (mem_write_lock.l_pid == -1) {
388 mem_write_lock.l_pid = getpid();
389 }
390 #endif
391
392 while (1) {
393 if (fcntl(lock_file, F_SETLKW, &mem_write_lock) == -1) {
394 if (errno == EINTR) {
395 continue;
396 }
397 zend_accel_error(ACCEL_LOG_ERROR, "Cannot create lock - %s (%d)", strerror(errno), errno);
398 }
399 break;
400 }
401 #else
402 zend_shared_alloc_lock_win32();
403 #endif
404
405 ZCG(locked) = 1;
406 }
407
408 void zend_shared_alloc_unlock(void)
409 {
410 ZCG(locked) = 0;
411
412 #ifndef ZEND_WIN32
413 if (fcntl(lock_file, F_SETLK, &mem_write_unlock) == -1) {
414 zend_accel_error(ACCEL_LOG_ERROR, "Cannot remove lock - %s (%d)", strerror(errno), errno);
415 }
416 #ifdef ZTS
417 tsrm_mutex_unlock(zts_lock);
418 #endif
419 #else
420 zend_shared_alloc_unlock_win32();
421 #endif
422 }
423
424 void zend_shared_alloc_init_xlat_table(void)
425 {
426
427
428
429
430
431
432
433 zend_hash_init(&ZCG(xlat_table), 128, NULL, NULL, 1);
434 }
435
436 void zend_shared_alloc_destroy_xlat_table(void)
437 {
438
439 zend_hash_destroy(&ZCG(xlat_table));
440 }
441
442 void zend_shared_alloc_clear_xlat_table(void)
443 {
444 zend_hash_clean(&ZCG(xlat_table));
445 }
446
447 void zend_shared_alloc_register_xlat_entry(const void *old, const void *new)
448 {
449 zend_hash_index_add_new_ptr(&ZCG(xlat_table), (zend_ulong)old, (void*)new);
450 }
451
452 void *zend_shared_alloc_get_xlat_entry(const void *old)
453 {
454 void *retval;
455
456 if ((retval = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)old)) == NULL) {
457 return NULL;
458 }
459 return retval;
460 }
461
462 size_t zend_shared_alloc_get_free_memory(void)
463 {
464 return ZSMMG(shared_free);
465 }
466
467 void zend_shared_alloc_save_state(void)
468 {
469 int i;
470
471 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
472 ZSMMG(shared_memory_state).positions[i] = ZSMMG(shared_segments)[i]->pos;
473 }
474 ZSMMG(shared_memory_state).shared_free = ZSMMG(shared_free);
475 }
476
477 void zend_shared_alloc_restore_state(void)
478 {
479 int i;
480
481 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
482 ZSMMG(shared_segments)[i]->pos = ZSMMG(shared_memory_state).positions[i];
483 }
484 ZSMMG(shared_free) = ZSMMG(shared_memory_state).shared_free;
485 ZSMMG(memory_exhausted) = 0;
486 ZSMMG(wasted_shared_memory) = 0;
487 }
488
489 const char *zend_accel_get_shared_model(void)
490 {
491 return g_shared_model;
492 }
493
494 void zend_accel_shared_protect(int mode)
495 {
496 #ifdef HAVE_MPROTECT
497 int i;
498
499 if (!smm_shared_globals) {
500 return;
501 }
502
503 if (mode) {
504 mode = PROT_READ;
505 } else {
506 mode = PROT_READ|PROT_WRITE;
507 }
508
509 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
510 mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->size, mode);
511 }
512 #endif
513 }
514
515 int zend_accel_in_shm(void *ptr)
516 {
517 int i;
518
519 if (!smm_shared_globals) {
520 return 0;
521 }
522
523 for (i = 0; i < ZSMMG(shared_segments_count); i++) {
524 if ((char*)ptr >= (char*)ZSMMG(shared_segments)[i]->p &&
525 (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->size) {
526 return 1;
527 }
528 }
529 return 0;
530 }