source: trunk/xcache/xc_shm_mmap.c @ 1154

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

avoid using rand() without seed. use getpid

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