source: trunk/xcache/xc_shm_mmap.c

Last change on this file was 1468, checked in by moo, 10 months ago

clean up shm handlers

  • Property svn:eol-style set to native
File size: 6.2 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"
[1468]32
33typedef struct xc_mmap_shm_t xc_shm_t;
34#define XC_SHM_T_DEFINED
[148]35#include "xc_shm.h"
[982]36#include "xc_utils.h"
[1]37
38#ifndef max
39#define max(a, b) ((a) < (b) ? (b) : (a))
40#endif
41
[302]42/* {{{ xc_shm_t */
[1468]43struct xc_mmap_shm_t {
44    xc_shm_base_t base;
[1]45    void *ptr;
46    void *ptr_ro;
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_IS_READWRITE(xc_mmap_is_readwrite) /* {{{ */
[1]64{
65    return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
66}
67/* }}} */
[148]68static XC_SHM_IS_READONLY(xc_mmap_is_readonly) /* {{{ */
[1]69{
[1468]70    return xc_shm_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
[1]71}
72/* }}} */
73
[148]74static XC_SHM_DESTROY(xc_mmap_destroy) /* {{{ */
[1]75{
76    if (shm->ptr_ro) {
77        munmap(shm->ptr_ro, shm->size);
78        /*
79        shm->ptr_ro = NULL;
80        */
81    }
82    if (shm->ptr) {
83        /* shm->size depends on shm->ptr */
84        munmap(shm->ptr, shm->size);
85        /*
86        shm->ptr = NULL;
87        */
88    }
[11]89#ifdef ZEND_WIN32
90    if (shm->hmap) {
91        CloseHandle(shm->hmap);
92    }
93    if (shm->hmap_ro) {
94        CloseHandle(shm->hmap_ro);
95    }
96#endif
97
98    if (shm->name) {
[924]99#ifndef ZEND_WIN32
100#   ifdef __CYGWIN__
[57]101        if (shm->newfile) {
102            unlink(shm->name);
103        }
[924]104#   endif
[11]105#endif
106        free(shm->name);
107    }
[1]108    /*
109    shm->size = NULL;
[1468]110    shm->base.readonlydiff = 0;
[1]111    */
112
113    free(shm);
114    return;
115}
116/* }}} */
[148]117static XC_SHM_INIT(xc_mmap_init) /* {{{ */
[1]118{
[21]119#ifdef ZEND_WIN32
120#   define TMP_PATH "XCache"
121#else
122#   define TMP_PATH "/tmp/XCache"
[924]123    int fd = -1;
[21]124#endif
[1]125    xc_shm_t *shm = NULL;
126    int ro_ok;
127    volatile void *romem;
[1154]128    char tmpname[sizeof(TMP_PATH) - 1 + 4 * 10 + 100] = { 0 };
[119]129    const char *errstr = NULL;
[148]130    const char *path = (const char *) arg1;
[1154]131    static int instanceId = 0;
[1]132
133    CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
134    shm->size = size;
[11]135
[1]136    if (path == NULL || !path[0]) {
[1154]137        snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d", TMP_PATH, (int) getuid(), (int) getpid(), ++instanceId);
[11]138        path = tmpname;
[1]139    }
[83]140#ifdef ZEND_WIN32
141    else {
[1154]142        snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d", path, (int) getuid(), (int) getpid(), ++instanceId);
[83]143        path = tmpname;
144    }
145#endif
[11]146
147    shm->name = strdup(path);
148
149#ifndef ZEND_WIN32
150#   define XCACHE_MMAP_PERMISSION (S_IRUSR | S_IWUSR)
151    fd = open(shm->name, O_RDWR, XCACHE_MMAP_PERMISSION);
[1]152    if (fd == -1) {
[61]153        /* do not create file in /dev */
154        if (strncmp(shm->name, "/dev", 4) == 0) {
[119]155            perror(shm->name);
[337]156            errstr = "Cannot open file set by xcache.mmap_path, check the xcache.size/var_size against system limitation";
[61]157            goto err;
158        }
[11]159        fd = open(shm->name, O_CREAT | O_RDWR, XCACHE_MMAP_PERMISSION);
[57]160        shm->newfile = 1;
[1]161        if (fd == -1) {
[119]162            perror(shm->name);
[337]163            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]164            goto err;
165        }
166    }
[767]167
[768]168    if (ftruncate(fd, size) != 0 && errno != EINVAL) {
[767]169        perror(shm->name);
170        errstr = "Failed to ftruncate the file";
171        goto err;
172    }
[11]173#endif
[1]174
[11]175#ifdef ZEND_WIN32
[57]176    shm->hmap = XCacheCreateFileMapping(size, PAGE_READWRITE, shm->name);
[11]177    shm->ptr = (LPSTR) MapViewOfFile(shm->hmap, FILE_MAP_WRITE, 0, 0, 0);
178#else
[1]179    shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
[11]180#endif
181
182    if (shm->ptr == XCACHE_MAP_FAILED) {
[119]183        perror(shm->name);
[558]184        errstr = "Failed creating file mapping";
[1]185        shm->ptr = NULL;
186        goto err;
187    }
188
[79]189    /* {{{ readonly protection, mmap it readonly and check if ptr_ro works */
[1]190    if (readonly_protection) {
[79]191        ro_ok = 0;
192
[11]193#ifdef ZEND_WIN32
[57]194        shm->hmap_ro = XCacheCreateFileMapping(size, PAGE_READONLY, shm->name);
[11]195        shm->ptr_ro = (LPSTR) MapViewOfFile(shm->hmap_ro, FILE_MAP_READ, 0, 0, 0);
196#else
[1]197        shm->ptr_ro = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
[11]198#endif
[79]199        if (shm->ptr_ro == XCACHE_MAP_FAILED) {
200            shm->ptr_ro = NULL;
201        }
[1]202        romem = shm->ptr_ro;
203
204        do {
[79]205            if (romem == NULL || romem == shm->ptr) {
[1]206                break;
207            }
208            *(char *)shm->ptr = 1;
209            if (*(char *)romem != 1) {
210                break;
211            }
212            *(char *)shm->ptr = 2;
213            if (*(char *)romem != 2) {
214                break;
215            }
216            ro_ok = 1;
217        } while (0);
218
[79]219        if (ro_ok) {
[1468]220            shm->base.readonlydiff = PTR_SUB(shm->ptr_ro, (char *) shm->ptr);
[79]221            /* no overlap */
[1468]222            assert((xc_shmsize_t) abs(shm->base.readonlydiff) >= size);
[1]223        }
[79]224        else {
225            if (shm->ptr_ro) {
226                munmap(shm->ptr_ro, size);
227            }
228#ifdef ZEND_WIN32
229            if (shm->hmap_ro) {
230                CloseHandle(shm->hmap_ro);
231            }
232#endif
233            shm->ptr_ro = NULL;
[1468]234            shm->base.readonlydiff = 0;
[79]235        }
[1]236    }
[79]237
[1]238    /* }}} */
239
[924]240#ifndef ZEND_WIN32
[1]241    close(fd);
[924]242
243#   ifndef __CYGWIN__
[57]244    if (shm->newfile) {
245        unlink(shm->name);
246    }
[924]247#   endif
[11]248#endif
[1]249
250    return shm;
251
252err:
[924]253#ifndef ZEND_WIN32
[11]254    if (fd != -1) {
255        close(fd);
256    }
[924]257#endif
[1]258    if (shm) {
[148]259        xc_mmap_destroy(shm);
[1]260    }
[119]261    if (errstr) {
262        fprintf(stderr, "%s\n", errstr);
263        zend_error(E_ERROR, "%s", errstr);
264    }
[1]265    return NULL;
266}
267/* }}} */
268
[148]269static XC_SHM_MEMINIT(xc_mmap_meminit) /* {{{ */
[1]270{
[1135]271    void *mem;
[148]272    if (shm->memoffset + size > shm->size) {
273        zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
274        return NULL;
275    }
[1135]276    mem = PTR_ADD(shm->ptr, shm->memoffset);
[148]277    shm->memoffset += size;
278    return mem;
[1]279}
280/* }}} */
[148]281static XC_SHM_MEMDESTROY(xc_mmap_memdestroy) /* {{{ */
282{
283}
284/* }}} */
285
[1468]286static xc_shm_vtable_t xc_shm_mmap_vtable = XC_SHM_VTABLE(mmap);
[148]287void xc_shm_mmap_register() /* {{{ */
288{
[1468]289    if (xc_shm_scheme_register("mmap", &xc_shm_mmap_vtable) == 0) {
[148]290        zend_error(E_ERROR, "XCache: failed to register mmap shm_scheme");
291    }
292    return;
293}
294/* }}} */
Note: See TracBrowser for help on using the repository browser.