1 /*
2 +----------------------------------------------------------------------+
3 | APC |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2011 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: Rasmus Lerdorf <rasmus@php.net> |
16 +----------------------------------------------------------------------+
17
18 This software was contributed to PHP by Community Connect Inc. in 2002
19 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
20 Future revisions and derivatives of this source code must acknowledge
21 Community Connect Inc. as the original contributor of this module by
22 leaving this note intact in the source code.
23
24 All other licensing and usage conditions are those of the PHP Group.
25
26 */
27
28 #include "apc.h"
29 #include "apc_mmap.h"
30 #include "apc_lock.h"
31
32 #if APC_MMAP
33
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/mman.h>
37
38 /*
39 * Some operating systems (like FreeBSD) have a MAP_NOSYNC flag that
40 * tells whatever update daemons might be running to not flush dirty
41 * vm pages to disk unless absolutely necessary. My guess is that
42 * most systems that don't have this probably default to only synching
43 * to disk when absolutely necessary.
44 */
45 #ifndef MAP_NOSYNC
46 #define MAP_NOSYNC 0
47 #endif
48
49 /* support for systems where MAP_ANONYMOUS is defined but not MAP_ANON, ie: HP-UX bug #14615 */
50 #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
51 # define MAP_ANON MAP_ANONYMOUS
52 #endif
53
apc_mmap(char * file_mask,size_t size)54 apc_segment_t apc_mmap(char *file_mask, size_t size)
55 {
56 apc_segment_t segment;
57
58 int fd = -1;
59 int flags = MAP_SHARED | MAP_NOSYNC;
60 #ifdef APC_MEMPROTECT
61 int remap = 1;
62 #endif
63
64 /* If no filename was provided, do an anonymous mmap */
65 if(!file_mask || (file_mask && !strlen(file_mask))) {
66 #if !defined(MAP_ANON)
67 zend_error_noreturn(E_CORE_ERROR, "Anonymous mmap does not appear to be available on this system (MAP_ANON/MAP_ANONYMOUS). Please see the apc.mmap_file_mask INI option.");
68 #else
69 fd = -1;
70 flags = MAP_SHARED | MAP_ANON;
71 #ifdef APC_MEMPROTECT
72 remap = 0;
73 #endif
74 #endif
75 } else if(!strcmp(file_mask,"/dev/zero")) {
76 fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
77 if(fd == -1) {
78 zend_error_noreturn(E_CORE_ERROR, "apc_mmap: open on /dev/zero failed");
79 }
80 #ifdef APC_MEMPROTECT
81 remap = 0; /* cannot remap */
82 #endif
83 } else {
84 /*
85 * Otherwise we do a normal filesystem mmap
86 */
87 fd = mkstemp(file_mask);
88 if(fd == -1) {
89 zend_error_noreturn(E_CORE_ERROR, "apc_mmap: mkstemp on %s failed", file_mask);
90 }
91 if (ftruncate(fd, size) < 0) {
92 close(fd);
93 unlink(file_mask);
94 zend_error_noreturn(E_CORE_ERROR, "apc_mmap: ftruncate failed");
95 }
96 unlink(file_mask);
97 }
98
99 segment.shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
100 segment.size = size;
101
102 #ifdef APC_MEMPROTECT
103 if(remap) {
104 segment.roaddr = (void *)mmap(NULL, size, PROT_READ, flags, fd, 0);
105 } else {
106 segment.roaddr = NULL;
107 }
108 #endif
109
110 if ((long)segment.shmaddr == -1) {
111 zend_error_noreturn(E_CORE_ERROR, "apc_mmap: Failed to mmap %zu bytes. Is your apc.shm_size too large?", size);
112 }
113
114 if (fd != -1) close(fd);
115
116 return segment;
117 }
118
apc_unmap(apc_segment_t * segment)119 void apc_unmap(apc_segment_t *segment)
120 {
121 if (munmap(segment->shmaddr, segment->size) < 0) {
122 apc_warning("apc_unmap: munmap failed");
123 }
124
125 #ifdef APC_MEMPROTECT
126 if (segment->roaddr && munmap(segment->roaddr, segment->size) < 0) {
127 apc_warning("apc_unmap: munmap failed");
128 }
129 #endif
130
131 }
132
133 #endif
134
135 /*
136 * Local variables:
137 * tab-width: 4
138 * c-basic-offset: 4
139 * End:
140 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
141 * vim<600: noexpandtab sw=4 ts=4 sts=4
142 */
143