XCache is a fast, stable PHP opcode cacher that has been proven and is now running on production servers under high load. https://xcache.lighttpd.net/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
5.2 KiB

  1. #undef ALLOC_DEBUG
  2. #include <stdio.h>
  3. #include <assert.h>
  4. #include <limits.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. /* mmap */
  8. #ifdef ZEND_WIN32
  9. # define ftruncate chsize
  10. # define getuid() 0
  11. # include <process.h>
  12. # define XCacheCreateFileMapping(size, perm, name) \
  13. CreateFileMapping(INVALID_HANDLE_VALUE, NULL, perm, (sizeof(xc_shmsize_t) > 4) ? size >> 32 : 0, size & 0xffffffff, name)
  14. # define XCACHE_MAP_FAILED NULL
  15. # define munmap(p, s) UnmapViewOfFile(p)
  16. #else
  17. # include <unistd.h>
  18. # define XCACHE_MAP_FAILED MAP_FAILED
  19. #endif
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <fcntl.h>
  23. #ifndef ZEND_WIN32
  24. #include <sys/mman.h>
  25. #endif
  26. #include "php.h"
  27. #include "myshm.h"
  28. #ifndef max
  29. #define max(a, b) ((a) < (b) ? (b) : (a))
  30. #endif
  31. // {{{ xc_shm_t
  32. struct _xc_shm_t {
  33. void *ptr;
  34. void *ptr_ro;
  35. long diff;
  36. xc_shmsize_t size;
  37. char *name;
  38. int newfile;
  39. #ifdef ZEND_WIN32
  40. HANDLE hmap;
  41. HANDLE hmap_ro;
  42. #endif
  43. };
  44. #undef NDEBUG
  45. #ifdef ALLOC_DEBUG
  46. # define inline
  47. #else
  48. # define NDEBUG
  49. #endif
  50. #include <assert.h>
  51. /* }}} */
  52. #define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
  53. #define PTR_ADD(ptr, v) (((char *) (ptr)) + (v))
  54. #define PTR_SUB(ptr, v) (((char *) (ptr)) - (v))
  55. int xc_shm_can_readonly(xc_shm_t *shm) /* {{{ */
  56. {
  57. return shm->ptr_ro != NULL;
  58. }
  59. /* }}} */
  60. int xc_shm_is_readwrite(xc_shm_t *shm, const void *p) /* {{{ */
  61. {
  62. return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
  63. }
  64. /* }}} */
  65. int xc_shm_is_readonly(xc_shm_t *shm, const void *p) /* {{{ */
  66. {
  67. return xc_shm_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
  68. }
  69. /* }}} */
  70. void *xc_shm_to_readwrite(xc_shm_t *shm, void *p) /* {{{ */
  71. {
  72. if (shm->diff) {
  73. assert(xc_shm_is_readonly(shm, p));
  74. p = PTR_SUB(p, shm->diff);
  75. }
  76. assert(xc_shm_is_readwrite(shm, p));
  77. return p;
  78. }
  79. /* }}} */
  80. void *xc_shm_to_readonly(xc_shm_t *shm, void *p) /* {{{ */
  81. {
  82. assert(xc_shm_is_readwrite(shm, p));
  83. if (shm->diff) {
  84. p = PTR_ADD(p, shm->diff);
  85. assert(xc_shm_is_readonly(shm, p));
  86. }
  87. return p;
  88. }
  89. /* }}} */
  90. void xc_shm_destroy(xc_shm_t *shm) /* {{{ */
  91. {
  92. if (shm->ptr_ro) {
  93. munmap(shm->ptr_ro, shm->size);
  94. /*
  95. shm->ptr_ro = NULL;
  96. */
  97. }
  98. if (shm->ptr) {
  99. /* shm->size depends on shm->ptr */
  100. munmap(shm->ptr, shm->size);
  101. /*
  102. shm->ptr = NULL;
  103. */
  104. }
  105. #ifdef ZEND_WIN32
  106. if (shm->hmap) {
  107. CloseHandle(shm->hmap);
  108. }
  109. if (shm->hmap_ro) {
  110. CloseHandle(shm->hmap_ro);
  111. }
  112. #endif
  113. if (shm->name) {
  114. #ifdef __CYGWIN__
  115. if (shm->newfile) {
  116. unlink(shm->name);
  117. }
  118. #endif
  119. free(shm->name);
  120. }
  121. /*
  122. shm->size = NULL;
  123. shm->diff = 0;
  124. */
  125. free(shm);
  126. return;
  127. }
  128. /* }}} */
  129. xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_protection) /* {{{ */
  130. {
  131. #ifdef ZEND_WIN32
  132. # define TMP_PATH "XCache"
  133. #else
  134. # define TMP_PATH "/tmp/XCache"
  135. #endif
  136. xc_shm_t *shm = NULL;
  137. int fd = -1;
  138. int ro_ok;
  139. volatile void *romem;
  140. char tmpname[sizeof(TMP_PATH) - 1 + 100];
  141. CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
  142. shm->size = size;
  143. if (path == NULL || !path[0]) {
  144. static int inc = 0;
  145. snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", TMP_PATH, (int) getuid(), (int) getpid(), inc ++, rand());
  146. path = tmpname;
  147. }
  148. #ifdef ZEND_WIN32
  149. else {
  150. static int inc2 = 0;
  151. snprintf(tmpname, sizeof(tmpname) - 1, "%s.%d.%d.%d.%d", path, (int) getuid(), (int) getpid(), inc2 ++, rand());
  152. path = tmpname;
  153. }
  154. #endif
  155. shm->name = strdup(path);
  156. #ifndef ZEND_WIN32
  157. # define XCACHE_MMAP_PERMISSION (S_IRUSR | S_IWUSR)
  158. fd = open(shm->name, O_RDWR, XCACHE_MMAP_PERMISSION);
  159. if (fd == -1) {
  160. /* do not create file in /dev */
  161. if (strncmp(shm->name, "/dev", 4) == 0) {
  162. goto err;
  163. }
  164. fd = open(shm->name, O_CREAT | O_RDWR, XCACHE_MMAP_PERMISSION);
  165. shm->newfile = 1;
  166. if (fd == -1) {
  167. goto err;
  168. }
  169. }
  170. ftruncate(fd, size);
  171. #endif
  172. #ifdef ZEND_WIN32
  173. shm->hmap = XCacheCreateFileMapping(size, PAGE_READWRITE, shm->name);
  174. shm->ptr = (LPSTR) MapViewOfFile(shm->hmap, FILE_MAP_WRITE, 0, 0, 0);
  175. #else
  176. shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  177. #endif
  178. if (shm->ptr == XCACHE_MAP_FAILED) {
  179. shm->ptr = NULL;
  180. goto err;
  181. }
  182. ro_ok = 0;
  183. if (readonly_protection) {
  184. #ifdef ZEND_WIN32
  185. shm->hmap_ro = XCacheCreateFileMapping(size, PAGE_READONLY, shm->name);
  186. shm->ptr_ro = (LPSTR) MapViewOfFile(shm->hmap_ro, FILE_MAP_READ, 0, 0, 0);
  187. #else
  188. shm->ptr_ro = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
  189. #endif
  190. if (shm->ptr_ro == XCACHE_MAP_FAILED) {
  191. shm->ptr_ro = NULL;
  192. }
  193. romem = shm->ptr_ro;
  194. /* {{{ check if ptr_ro works */
  195. do {
  196. if (shm->ptr_ro == NULL || shm->ptr_ro == shm->ptr) {
  197. break;
  198. }
  199. *(char *)shm->ptr = 1;
  200. if (*(char *)romem != 1) {
  201. break;
  202. }
  203. *(char *)shm->ptr = 2;
  204. if (*(char *)romem != 2) {
  205. break;
  206. }
  207. ro_ok = 1;
  208. } while (0);
  209. }
  210. if (ro_ok) {
  211. shm->diff = PTR_SUB(shm->ptr_ro, (char *) shm->ptr);
  212. assert(abs(shm->diff) >= size);
  213. }
  214. else {
  215. if (shm->ptr_ro) {
  216. munmap(shm->ptr_ro, size);
  217. }
  218. shm->ptr_ro = NULL;
  219. shm->diff = 0;
  220. }
  221. /* }}} */
  222. close(fd);
  223. #ifndef __CYGWIN__
  224. if (shm->newfile) {
  225. unlink(shm->name);
  226. }
  227. #endif
  228. return shm;
  229. err:
  230. if (fd != -1) {
  231. close(fd);
  232. }
  233. if (shm) {
  234. xc_shm_destroy(shm);
  235. }
  236. return NULL;
  237. }
  238. /* }}} */
  239. void *xc_shm_ptr(xc_shm_t *shm) /* {{{ */
  240. {
  241. return shm->ptr;
  242. }
  243. /* }}} */