source: trunk/mmap.c @ 979

Last change on this file since 979 was 979, checked in by moo, 2 years ago

closes #2: auto disable on crash

  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1
2#include <stdio.h>
3#include <assert.h>
4#include <limits.h>
5#include <string.h>
6#include <stdlib.h>
7
8/* mmap */
9#ifdef ZEND_WIN32
10#   define ftruncate chsize
11#   define getuid() 0
12#   include <process.h>
13#   define XCacheCreateFileMapping(size, perm, name) \
14        CreateFileMapping(INVALID_HANDLE_VALUE, NULL, perm, (sizeof(xc_shmsize_t) > 4) ? size >> 32 : 0, size & 0xffffffff, name)
15#   define XCACHE_MAP_FAILED NULL
16#   define munmap(p, s) UnmapViewOfFile(p)
17#else
18#   include <unistd.h>
19/* make sure to mark(change) it to NULL to keep consistent */
20#   define XCACHE_MAP_FAILED MAP_FAILED
21#endif
22
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26
27#ifndef ZEND_WIN32
28#include <sys/mman.h>
29#endif
30
31#include "php.h"
32#define XC_SHM_IMPL _xc_mmap_shm_t
33#include "xc_shm.h"
34#include "utils.h"
35
36#ifndef max
37#define max(a, b) ((a) < (b) ? (b) : (a))
38#endif
39
40/* {{{ xc_shm_t */
41struct _xc_mmap_shm_t {
42    xc_shm_handlers_t *handlers;
43    zend_bool disabled;
44    void *ptr;
45    void *ptr_ro;
46    long  diff;
47    xc_shmsize_t size;
48    xc_shmsize_t memoffset;
49    char *name;
50#ifdef ZEND_WIN32
51    HANDLE hmap;
52    HANDLE hmap_ro;
53#else
54    int newfile;
55#endif
56};
57
58/* }}} */
59#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
60#define PTR_ADD(ptr, v) (((char *) (ptr)) + (v))
61#define PTR_SUB(ptr, v) (((char *) (ptr)) - (v))
62
63static XC_SHM_CAN_READONLY(xc_mmap_can_readonly) /* {{{ */
64{
65    return shm->ptr_ro != NULL;
66}
67/* }}} */
68static XC_SHM_IS_READWRITE(xc_mmap_is_readwrite) /* {{{ */
69{
70    return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
71}
72/* }}} */
73static XC_SHM_IS_READONLY(xc_mmap_is_readonly) /* {{{ */
74{
75    return xc_mmap_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
76}
77/* }}} */
78static XC_SHM_TO_READWRITE(xc_mmap_to_readwrite) /* {{{ */
79{
80    if (shm->diff) {
81        assert(xc_mmap_is_readonly(shm, p));
82        p = PTR_SUB(p, shm->diff);
83    }
84    assert(xc_mmap_is_readwrite(shm, p));
85    return p;
86}
87/* }}} */
88static XC_SHM_TO_READONLY(xc_mmap_to_readonly) /* {{{ */
89{
90    assert(xc_mmap_is_readwrite(shm, p));
91    if (shm->diff) {
92        p = PTR_ADD(p, shm->diff);
93        assert(xc_mmap_is_readonly(shm, p));
94    }
95    return p;
96}
97/* }}} */
98
99static XC_SHM_DESTROY(xc_mmap_destroy) /* {{{ */
100{
101    if (shm->ptr_ro) {
102        munmap(shm->ptr_ro, shm->size);
103        /*
104        shm->ptr_ro = NULL;
105        */
106    }
107    if (shm->ptr) {
108        /* shm->size depends on shm->ptr */
109        munmap(shm->ptr, shm->size);
110        /*
111        shm->ptr = NULL;
112        */
113    }
114#ifdef ZEND_WIN32
115    if (shm->hmap) {
116        CloseHandle(shm->hmap);
117    }
118    if (shm->hmap_ro) {
119        CloseHandle(shm->hmap_ro);
120    }
121#endif
122
123    if (shm->name) {
124#ifndef ZEND_WIN32
125#   ifdef __CYGWIN__
126        if (shm->newfile) {
127            unlink(shm->name);
128        }
129#   endif
130#endif
131        free(shm->name);
132    }
133    /*
134    shm->size = NULL;
135    shm->diff = 0;
136    */
137
138    free(shm);
139    return;
140}
141/* }}} */
142static XC_SHM_INIT(xc_mmap_init) /* {{{ */
143{
144#ifdef ZEND_WIN32
145#   define TMP_PATH "XCache"
146#else
147#   define TMP_PATH "/tmp/XCache"
148    int fd = -1;
149#endif
150    xc_shm_t *shm = NULL;
151    int ro_ok;
152    volatile void *romem;
153    char tmpname[sizeof(TMP_PATH) - 1 + 100];
154    const char *errstr = NULL;
155    const char *path = (const char *) arg1;
156
157    CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
158    shm->size = size;
159
160    if (path == NULL || !path[0]) {
161        static int inc = 0;
162        snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", TMP_PATH, (int) getuid(), (int) getpid(), inc ++, rand());
163        path = tmpname;
164    }
165#ifdef ZEND_WIN32
166    else {
167        static int inc2 = 0;
168        snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", path, (int) getuid(), (int) getpid(), inc2 ++, rand());
169        path = tmpname;
170    }
171#endif
172
173    shm->name = strdup(path);
174
175#ifndef ZEND_WIN32
176#   define XCACHE_MMAP_PERMISSION (S_IRUSR | S_IWUSR)
177    fd = open(shm->name, O_RDWR, XCACHE_MMAP_PERMISSION);
178    if (fd == -1) {
179        /* do not create file in /dev */
180        if (strncmp(shm->name, "/dev", 4) == 0) {
181            perror(shm->name);
182            errstr = "Cannot open file set by xcache.mmap_path, check the xcache.size/var_size against system limitation";
183            goto err;
184        }
185        fd = open(shm->name, O_CREAT | O_RDWR, XCACHE_MMAP_PERMISSION);
186        shm->newfile = 1;
187        if (fd == -1) {
188            perror(shm->name);
189            errstr = "Cannot open or create file set by xcache.mmap_path, check the path permission or check xcache.size/var_size against system limitation";
190            goto err;
191        }
192    }
193
194    if (ftruncate(fd, size) != 0 && errno != EINVAL) {
195        perror(shm->name);
196        errstr = "Failed to ftruncate the file";
197        goto err;
198    }
199#endif
200
201#ifdef ZEND_WIN32
202    shm->hmap = XCacheCreateFileMapping(size, PAGE_READWRITE, shm->name);
203    shm->ptr = (LPSTR) MapViewOfFile(shm->hmap, FILE_MAP_WRITE, 0, 0, 0);
204#else
205    shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
206#endif
207
208    if (shm->ptr == XCACHE_MAP_FAILED) {
209        perror(shm->name);
210        errstr = "Failed creating file mapping";
211        shm->ptr = NULL;
212        goto err;
213    }
214
215    /* {{{ readonly protection, mmap it readonly and check if ptr_ro works */
216    if (readonly_protection) {
217        ro_ok = 0;
218
219#ifdef ZEND_WIN32
220        shm->hmap_ro = XCacheCreateFileMapping(size, PAGE_READONLY, shm->name);
221        shm->ptr_ro = (LPSTR) MapViewOfFile(shm->hmap_ro, FILE_MAP_READ, 0, 0, 0);
222#else
223        shm->ptr_ro = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
224#endif
225        if (shm->ptr_ro == XCACHE_MAP_FAILED) {
226            shm->ptr_ro = NULL;
227        }
228        romem = shm->ptr_ro;
229
230        do {
231            if (romem == NULL || romem == shm->ptr) {
232                break;
233            }
234            *(char *)shm->ptr = 1;
235            if (*(char *)romem != 1) {
236                break;
237            }
238            *(char *)shm->ptr = 2;
239            if (*(char *)romem != 2) {
240                break;
241            }
242            ro_ok = 1;
243        } while (0);
244
245        if (ro_ok) {
246            shm->diff = PTR_SUB(shm->ptr_ro, (char *) shm->ptr);
247            /* no overlap */
248            assert(abs(shm->diff) >= size);
249        }
250        else {
251            if (shm->ptr_ro) {
252                munmap(shm->ptr_ro, size);
253            }
254#ifdef ZEND_WIN32
255            if (shm->hmap_ro) {
256                CloseHandle(shm->hmap_ro);
257            }
258#endif
259            shm->ptr_ro = NULL;
260            shm->diff = 0;
261        }
262    }
263
264    /* }}} */
265
266#ifndef ZEND_WIN32
267    close(fd);
268
269#   ifndef __CYGWIN__
270    if (shm->newfile) {
271        unlink(shm->name);
272    }
273#   endif
274#endif
275
276    return shm;
277
278err:
279#ifndef ZEND_WIN32
280    if (fd != -1) {
281        close(fd);
282    }
283#endif
284    if (shm) {
285        xc_mmap_destroy(shm);
286    }
287    if (errstr) {
288        fprintf(stderr, "%s\n", errstr);
289        zend_error(E_ERROR, "%s", errstr);
290    }
291    return NULL;
292}
293/* }}} */
294
295static XC_SHM_MEMINIT(xc_mmap_meminit) /* {{{ */
296{
297    xc_mem_t *mem;
298    if (shm->memoffset + size > shm->size) {
299        zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
300        return NULL;
301    }
302    mem = (xc_mem_t *) PTR_ADD(shm->ptr, shm->memoffset);
303    shm->memoffset += size;
304    mem->handlers = shm->handlers->memhandlers;
305    mem->handlers->init(shm, mem, size);
306    return mem;
307}
308/* }}} */
309static XC_SHM_MEMDESTROY(xc_mmap_memdestroy) /* {{{ */
310{
311}
312/* }}} */
313
314static xc_shm_handlers_t xc_shm_mmap_handlers = XC_SHM_HANDLERS(mmap);
315void xc_shm_mmap_register() /* {{{ */
316{
317    CHECK(xc_shm_mmap_handlers.memhandlers = xc_mem_scheme_find("mem"), "cannot find mem handlers");
318    if (xc_shm_scheme_register("mmap", &xc_shm_mmap_handlers) == 0) {
319        zend_error(E_ERROR, "XCache: failed to register mmap shm_scheme");
320    }
321err:
322    return;
323}
324/* }}} */
Note: See TracBrowser for help on using the repository browser.