2006-05-09 10:58:38 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2006-05-24 07:52:48 +00:00
|
|
|
|
2006-05-09 10:58:38 +00:00
|
|
|
/* mmap */
|
2006-05-24 07:52:48 +00:00
|
|
|
#ifdef ZEND_WIN32
|
|
|
|
# define ftruncate chsize
|
|
|
|
# define getuid() 0
|
2006-06-18 01:27:30 +00:00
|
|
|
# include <process.h>
|
2006-06-02 01:55:05 +00:00
|
|
|
# define XCacheCreateFileMapping(size, perm, name) \
|
2006-05-24 07:52:48 +00:00
|
|
|
CreateFileMapping(INVALID_HANDLE_VALUE, NULL, perm, (sizeof(xc_shmsize_t) > 4) ? size >> 32 : 0, size & 0xffffffff, name)
|
|
|
|
# define XCACHE_MAP_FAILED NULL
|
|
|
|
# define munmap(p, s) UnmapViewOfFile(p)
|
|
|
|
#else
|
|
|
|
# include <unistd.h>
|
2006-06-16 00:50:51 +00:00
|
|
|
/* make sure to mark(change) it to NULL to keep consistent */
|
2006-05-24 07:52:48 +00:00
|
|
|
# define XCACHE_MAP_FAILED MAP_FAILED
|
|
|
|
#endif
|
|
|
|
|
2006-05-09 10:58:38 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2006-05-24 07:52:48 +00:00
|
|
|
|
|
|
|
#ifndef ZEND_WIN32
|
2006-05-09 10:58:38 +00:00
|
|
|
#include <sys/mman.h>
|
2006-05-24 07:52:48 +00:00
|
|
|
#endif
|
2006-05-09 10:58:38 +00:00
|
|
|
|
|
|
|
#include "php.h"
|
2007-05-10 01:26:12 +00:00
|
|
|
#define XC_SHM_IMPL _xc_mmap_shm_t
|
2006-09-09 00:56:44 +00:00
|
|
|
#include "xc_shm.h"
|
2006-12-08 16:11:19 +00:00
|
|
|
#include "utils.h"
|
2006-05-09 10:58:38 +00:00
|
|
|
|
|
|
|
#ifndef max
|
|
|
|
#define max(a, b) ((a) < (b) ? (b) : (a))
|
|
|
|
#endif
|
|
|
|
|
2006-12-07 14:13:38 +00:00
|
|
|
/* {{{ xc_shm_t */
|
2007-05-10 01:26:12 +00:00
|
|
|
struct _xc_mmap_shm_t {
|
2006-09-09 00:56:44 +00:00
|
|
|
xc_shm_handlers_t *handlers;
|
2006-05-09 10:58:38 +00:00
|
|
|
void *ptr;
|
|
|
|
void *ptr_ro;
|
|
|
|
long diff;
|
|
|
|
xc_shmsize_t size;
|
2006-05-24 07:52:48 +00:00
|
|
|
char *name;
|
2006-06-02 01:55:05 +00:00
|
|
|
int newfile;
|
2006-09-09 00:56:44 +00:00
|
|
|
xc_shmsize_t memoffset;
|
2006-05-24 07:52:48 +00:00
|
|
|
#ifdef ZEND_WIN32
|
|
|
|
HANDLE hmap;
|
|
|
|
HANDLE hmap_ro;
|
|
|
|
#endif
|
2006-05-09 10:58:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* }}} */
|
|
|
|
#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
|
2006-05-24 07:52:48 +00:00
|
|
|
#define PTR_ADD(ptr, v) (((char *) (ptr)) + (v))
|
|
|
|
#define PTR_SUB(ptr, v) (((char *) (ptr)) - (v))
|
2006-05-09 10:58:38 +00:00
|
|
|
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_CAN_READONLY(xc_mmap_can_readonly) /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
|
|
|
return shm->ptr_ro != NULL;
|
|
|
|
}
|
|
|
|
/* }}} */
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_IS_READWRITE(xc_mmap_is_readwrite) /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
|
|
|
return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
|
|
|
|
}
|
|
|
|
/* }}} */
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_IS_READONLY(xc_mmap_is_readonly) /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
2006-09-09 00:56:44 +00:00
|
|
|
return xc_mmap_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
|
2006-05-09 10:58:38 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_TO_READWRITE(xc_mmap_to_readwrite) /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
|
|
|
if (shm->diff) {
|
2006-09-18 06:05:46 +00:00
|
|
|
assert(xc_mmap_is_readonly(shm, p));
|
2006-06-03 03:07:38 +00:00
|
|
|
p = PTR_SUB(p, shm->diff);
|
2006-05-09 10:58:38 +00:00
|
|
|
}
|
2006-09-18 06:05:46 +00:00
|
|
|
assert(xc_mmap_is_readwrite(shm, p));
|
2006-05-09 10:58:38 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
/* }}} */
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_TO_READONLY(xc_mmap_to_readonly) /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
2006-09-18 06:05:46 +00:00
|
|
|
assert(xc_mmap_is_readwrite(shm, p));
|
2006-05-09 10:58:38 +00:00
|
|
|
if (shm->diff) {
|
2006-05-24 07:52:48 +00:00
|
|
|
p = PTR_ADD(p, shm->diff);
|
2006-09-18 06:05:46 +00:00
|
|
|
assert(xc_mmap_is_readonly(shm, p));
|
2006-05-09 10:58:38 +00:00
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_DESTROY(xc_mmap_destroy) /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
|
|
|
if (shm->ptr_ro) {
|
|
|
|
munmap(shm->ptr_ro, shm->size);
|
|
|
|
/*
|
|
|
|
shm->ptr_ro = NULL;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
if (shm->ptr) {
|
|
|
|
/* shm->size depends on shm->ptr */
|
|
|
|
munmap(shm->ptr, shm->size);
|
|
|
|
/*
|
|
|
|
shm->ptr = NULL;
|
|
|
|
*/
|
|
|
|
}
|
2006-05-24 07:52:48 +00:00
|
|
|
#ifdef ZEND_WIN32
|
|
|
|
if (shm->hmap) {
|
|
|
|
CloseHandle(shm->hmap);
|
|
|
|
}
|
|
|
|
if (shm->hmap_ro) {
|
|
|
|
CloseHandle(shm->hmap_ro);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (shm->name) {
|
|
|
|
#ifdef __CYGWIN__
|
2006-06-02 01:55:05 +00:00
|
|
|
if (shm->newfile) {
|
|
|
|
unlink(shm->name);
|
|
|
|
}
|
2006-05-24 07:52:48 +00:00
|
|
|
#endif
|
|
|
|
free(shm->name);
|
|
|
|
}
|
2006-05-09 10:58:38 +00:00
|
|
|
/*
|
|
|
|
shm->size = NULL;
|
|
|
|
shm->diff = 0;
|
|
|
|
*/
|
|
|
|
|
|
|
|
free(shm);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* }}} */
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_INIT(xc_mmap_init) /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
2006-05-25 02:39:16 +00:00
|
|
|
#ifdef ZEND_WIN32
|
|
|
|
# define TMP_PATH "XCache"
|
|
|
|
#else
|
|
|
|
# define TMP_PATH "/tmp/XCache"
|
|
|
|
#endif
|
2006-05-09 10:58:38 +00:00
|
|
|
xc_shm_t *shm = NULL;
|
2006-05-24 07:52:48 +00:00
|
|
|
int fd = -1;
|
2006-05-09 10:58:38 +00:00
|
|
|
int ro_ok;
|
|
|
|
volatile void *romem;
|
2006-05-25 02:39:16 +00:00
|
|
|
char tmpname[sizeof(TMP_PATH) - 1 + 100];
|
2006-08-31 23:45:54 +00:00
|
|
|
const char *errstr = NULL;
|
2006-09-09 00:56:44 +00:00
|
|
|
const char *path = (const char *) arg1;
|
2006-05-09 10:58:38 +00:00
|
|
|
|
|
|
|
CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
|
|
|
|
shm->size = size;
|
2006-05-24 07:52:48 +00:00
|
|
|
|
2006-05-09 10:58:38 +00:00
|
|
|
if (path == NULL || !path[0]) {
|
2006-05-24 07:52:48 +00:00
|
|
|
static int inc = 0;
|
2006-06-18 01:27:30 +00:00
|
|
|
snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", TMP_PATH, (int) getuid(), (int) getpid(), inc ++, rand());
|
2006-05-24 07:52:48 +00:00
|
|
|
path = tmpname;
|
2006-05-09 10:58:38 +00:00
|
|
|
}
|
2006-06-18 01:27:30 +00:00
|
|
|
#ifdef ZEND_WIN32
|
|
|
|
else {
|
|
|
|
static int inc2 = 0;
|
|
|
|
snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", path, (int) getuid(), (int) getpid(), inc2 ++, rand());
|
|
|
|
path = tmpname;
|
|
|
|
}
|
|
|
|
#endif
|
2006-05-24 07:52:48 +00:00
|
|
|
|
|
|
|
shm->name = strdup(path);
|
|
|
|
|
|
|
|
#ifndef ZEND_WIN32
|
|
|
|
# define XCACHE_MMAP_PERMISSION (S_IRUSR | S_IWUSR)
|
|
|
|
fd = open(shm->name, O_RDWR, XCACHE_MMAP_PERMISSION);
|
2006-05-09 10:58:38 +00:00
|
|
|
if (fd == -1) {
|
2006-06-05 05:13:34 +00:00
|
|
|
/* do not create file in /dev */
|
|
|
|
if (strncmp(shm->name, "/dev", 4) == 0) {
|
2006-08-31 23:45:54 +00:00
|
|
|
perror(shm->name);
|
2006-12-17 03:20:43 +00:00
|
|
|
errstr = "Cannot open file set by xcache.mmap_path, check the xcache.size/var_size against system limitation";
|
2006-06-05 05:13:34 +00:00
|
|
|
goto err;
|
|
|
|
}
|
2006-05-24 07:52:48 +00:00
|
|
|
fd = open(shm->name, O_CREAT | O_RDWR, XCACHE_MMAP_PERMISSION);
|
2006-06-02 01:55:05 +00:00
|
|
|
shm->newfile = 1;
|
2006-05-09 10:58:38 +00:00
|
|
|
if (fd == -1) {
|
2006-08-31 23:45:54 +00:00
|
|
|
perror(shm->name);
|
2006-12-17 03:20:43 +00:00
|
|
|
errstr = "Cannot open or create file set by xcache.mmap_path, check the path permission or check xcache.size/var_size against system limitation";
|
2006-05-09 10:58:38 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ftruncate(fd, size);
|
2006-05-24 07:52:48 +00:00
|
|
|
#endif
|
2006-05-09 10:58:38 +00:00
|
|
|
|
2006-05-24 07:52:48 +00:00
|
|
|
#ifdef ZEND_WIN32
|
2006-06-02 01:55:05 +00:00
|
|
|
shm->hmap = XCacheCreateFileMapping(size, PAGE_READWRITE, shm->name);
|
2006-05-24 07:52:48 +00:00
|
|
|
shm->ptr = (LPSTR) MapViewOfFile(shm->hmap, FILE_MAP_WRITE, 0, 0, 0);
|
|
|
|
#else
|
2006-05-09 10:58:38 +00:00
|
|
|
shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
2006-05-24 07:52:48 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (shm->ptr == XCACHE_MAP_FAILED) {
|
2006-08-31 23:45:54 +00:00
|
|
|
perror(shm->name);
|
|
|
|
errstr = "Failed creating file mappping";
|
2006-05-09 10:58:38 +00:00
|
|
|
shm->ptr = NULL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2006-06-16 00:50:51 +00:00
|
|
|
/* {{{ readonly protection, mmap it readonly and check if ptr_ro works */
|
2006-05-09 10:58:38 +00:00
|
|
|
if (readonly_protection) {
|
2006-06-16 00:50:51 +00:00
|
|
|
ro_ok = 0;
|
|
|
|
|
2006-05-24 07:52:48 +00:00
|
|
|
#ifdef ZEND_WIN32
|
2006-06-02 01:55:05 +00:00
|
|
|
shm->hmap_ro = XCacheCreateFileMapping(size, PAGE_READONLY, shm->name);
|
2006-05-24 07:52:48 +00:00
|
|
|
shm->ptr_ro = (LPSTR) MapViewOfFile(shm->hmap_ro, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
#else
|
2006-05-09 10:58:38 +00:00
|
|
|
shm->ptr_ro = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
2006-05-24 07:52:48 +00:00
|
|
|
#endif
|
2006-06-16 00:50:51 +00:00
|
|
|
if (shm->ptr_ro == XCACHE_MAP_FAILED) {
|
|
|
|
shm->ptr_ro = NULL;
|
|
|
|
}
|
2006-05-09 10:58:38 +00:00
|
|
|
romem = shm->ptr_ro;
|
|
|
|
|
|
|
|
do {
|
2006-06-16 00:50:51 +00:00
|
|
|
if (romem == NULL || romem == shm->ptr) {
|
2006-05-09 10:58:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
*(char *)shm->ptr = 1;
|
|
|
|
if (*(char *)romem != 1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*(char *)shm->ptr = 2;
|
|
|
|
if (*(char *)romem != 2) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ro_ok = 1;
|
|
|
|
} while (0);
|
|
|
|
|
2006-06-16 00:50:51 +00:00
|
|
|
if (ro_ok) {
|
|
|
|
shm->diff = PTR_SUB(shm->ptr_ro, (char *) shm->ptr);
|
|
|
|
/* no overlap */
|
|
|
|
assert(abs(shm->diff) >= size);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (shm->ptr_ro) {
|
|
|
|
munmap(shm->ptr_ro, size);
|
|
|
|
}
|
|
|
|
#ifdef ZEND_WIN32
|
|
|
|
if (shm->hmap_ro) {
|
|
|
|
CloseHandle(shm->hmap_ro);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
shm->ptr_ro = NULL;
|
|
|
|
shm->diff = 0;
|
2006-05-09 10:58:38 +00:00
|
|
|
}
|
|
|
|
}
|
2006-06-16 00:50:51 +00:00
|
|
|
|
2006-05-09 10:58:38 +00:00
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
close(fd);
|
2006-05-24 07:52:48 +00:00
|
|
|
#ifndef __CYGWIN__
|
2006-06-02 01:55:05 +00:00
|
|
|
if (shm->newfile) {
|
|
|
|
unlink(shm->name);
|
|
|
|
}
|
2006-05-24 07:52:48 +00:00
|
|
|
#endif
|
2006-05-09 10:58:38 +00:00
|
|
|
|
|
|
|
return shm;
|
|
|
|
|
|
|
|
err:
|
2006-05-24 07:52:48 +00:00
|
|
|
if (fd != -1) {
|
|
|
|
close(fd);
|
|
|
|
}
|
2006-05-09 10:58:38 +00:00
|
|
|
if (shm) {
|
2006-09-09 00:56:44 +00:00
|
|
|
xc_mmap_destroy(shm);
|
2006-05-09 10:58:38 +00:00
|
|
|
}
|
2006-08-31 23:45:54 +00:00
|
|
|
if (errstr) {
|
|
|
|
fprintf(stderr, "%s\n", errstr);
|
|
|
|
zend_error(E_ERROR, "%s", errstr);
|
|
|
|
}
|
2006-05-09 10:58:38 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2006-09-09 00:56:44 +00:00
|
|
|
static XC_SHM_MEMINIT(xc_mmap_meminit) /* {{{ */
|
|
|
|
{
|
|
|
|
xc_mem_t *mem;
|
|
|
|
if (shm->memoffset + size > shm->size) {
|
|
|
|
zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
mem = (xc_mem_t *) PTR_ADD(shm->ptr, shm->memoffset);
|
|
|
|
shm->memoffset += size;
|
|
|
|
mem->handlers = shm->handlers->memhandlers;
|
|
|
|
mem->handlers->init(shm, mem, size);
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
static XC_SHM_MEMDESTROY(xc_mmap_memdestroy) /* {{{ */
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
static xc_shm_handlers_t xc_shm_mmap_handlers = XC_SHM_HANDLERS(mmap);
|
|
|
|
void xc_shm_mmap_register() /* {{{ */
|
2006-05-09 10:58:38 +00:00
|
|
|
{
|
2006-09-09 00:56:44 +00:00
|
|
|
CHECK(xc_shm_mmap_handlers.memhandlers = xc_mem_scheme_find("mem"), "cannot find mem handlers");
|
|
|
|
if (xc_shm_scheme_register("mmap", &xc_shm_mmap_handlers) == 0) {
|
|
|
|
zend_error(E_ERROR, "XCache: failed to register mmap shm_scheme");
|
|
|
|
}
|
|
|
|
err:
|
|
|
|
return;
|
2006-05-09 10:58:38 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|