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.
 
 
 
 
 
 

246 lines
5.3 KiB

  1. #define XC_SHM_IMPL _xc_malloc_shm_t
  2. #define _xc_allocator_t _xc_allocator_malloc_t
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include "xc_shm.h"
  7. #include "xc_allocator.h"
  8. #ifndef TEST
  9. #include "xcache.h"
  10. #endif
  11. #include "util/xc_align.h"
  12. struct _xc_allocator_malloc_t {
  13. const xc_allocator_vtable_t *vtable;
  14. xc_shm_t *shm;
  15. xc_memsize_t size;
  16. xc_memsize_t avail; /* total free */
  17. };
  18. /* {{{ _xc_malloc_shm_t */
  19. struct _xc_malloc_shm_t {
  20. xc_shm_handlers_t *handlers;
  21. xc_shmsize_t size;
  22. xc_shmsize_t memoffset;
  23. #ifndef TEST
  24. HashTable blocks;
  25. #endif
  26. };
  27. /* }}} */
  28. #ifndef TEST
  29. # define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)
  30. #else
  31. # define CHECK(x, e) do { if ((x) == NULL) { fprintf(stderr, "%s\n", "XCache: " e); goto err; } } while (0)
  32. #endif
  33. static void *xc_add_to_blocks(xc_allocator_t *allocator, void *p, size_t size) /* {{{ */
  34. {
  35. if (p) {
  36. #ifdef TEST
  37. allocator->avail -= size;
  38. #else
  39. zend_hash_add(&allocator->shm->blocks, (void *) &p, sizeof(p), (void *) &size, sizeof(size), NULL);
  40. #endif
  41. }
  42. return p;
  43. }
  44. /* }}} */
  45. static void xc_del_from_blocks(xc_allocator_t *allocator, void *p) /* {{{ */
  46. {
  47. #ifdef TEST
  48. /* TODO: allocator->avail += size; */
  49. #else
  50. zend_hash_del(&allocator->shm->blocks, (void *) &p, sizeof(p));
  51. #endif
  52. }
  53. /* }}} */
  54. static XC_ALLOCATOR_MALLOC(xc_allocator_malloc_malloc) /* {{{ */
  55. {
  56. return xc_add_to_blocks(allocator, malloc(size), size);
  57. }
  58. /* }}} */
  59. static XC_ALLOCATOR_FREE(xc_allocator_malloc_free) /* {{{ return block size freed */
  60. {
  61. xc_del_from_blocks(allocator, (void *) p);
  62. free((void *) p);
  63. return 0;
  64. }
  65. /* }}} */
  66. static XC_ALLOCATOR_CALLOC(xc_allocator_malloc_calloc) /* {{{ */
  67. {
  68. return xc_add_to_blocks(allocator, calloc(memb, size), size);
  69. }
  70. /* }}} */
  71. static XC_ALLOCATOR_REALLOC(xc_allocator_malloc_realloc) /* {{{ */
  72. {
  73. return xc_add_to_blocks(allocator, realloc((void *) p, size), size);
  74. }
  75. /* }}} */
  76. static XC_ALLOCATOR_AVAIL(xc_allocator_malloc_avail) /* {{{ */
  77. {
  78. return allocator->avail;
  79. }
  80. /* }}} */
  81. static XC_ALLOCATOR_SIZE(xc_allocator_malloc_size) /* {{{ */
  82. {
  83. return allocator->size;
  84. }
  85. /* }}} */
  86. static XC_ALLOCATOR_FREEBLOCK_FIRST(xc_allocator_malloc_freeblock_first) /* {{{ */
  87. {
  88. return (void *) -1;
  89. }
  90. /* }}} */
  91. static XC_ALLOCATOR_FREEBLOCK_NEXT(xc_allocator_malloc_freeblock_next) /* {{{ */
  92. {
  93. return NULL;
  94. }
  95. /* }}} */
  96. static XC_ALLOCATOR_BLOCK_SIZE(xc_allocator_malloc_block_size) /* {{{ */
  97. {
  98. return 0;
  99. }
  100. /* }}} */
  101. static XC_ALLOCATOR_BLOCK_OFFSET(xc_allocator_malloc_block_offset) /* {{{ */
  102. {
  103. return 0;
  104. }
  105. /* }}} */
  106. static XC_ALLOCATOR_INIT(xc_allocator_malloc_init) /* {{{ */
  107. {
  108. #define MINSIZE (ALIGN(sizeof(xc_allocator_t)))
  109. /* requires at least the header and 1 tail block */
  110. if (size < MINSIZE) {
  111. fprintf(stderr, "xc_allocator_malloc_init requires %lu bytes at least\n", (unsigned long) MINSIZE);
  112. return NULL;
  113. }
  114. allocator->shm = shm;
  115. allocator->size = size;
  116. allocator->avail = size - MINSIZE;
  117. #undef MINSIZE
  118. return allocator;
  119. }
  120. /* }}} */
  121. static XC_ALLOCATOR_DESTROY(xc_allocator_malloc_destroy) /* {{{ */
  122. {
  123. }
  124. /* }}} */
  125. static XC_SHM_CAN_READONLY(xc_malloc_can_readonly) /* {{{ */
  126. {
  127. return 0;
  128. }
  129. /* }}} */
  130. static XC_SHM_IS_READWRITE(xc_malloc_is_readwrite) /* {{{ */
  131. {
  132. #ifndef TEST
  133. HashPosition pos;
  134. size_t *psize;
  135. char **ptr;
  136. zend_hash_internal_pointer_reset_ex(&shm->blocks, &pos);
  137. while (zend_hash_get_current_data_ex(&shm->blocks, (void **) &psize, &pos) == SUCCESS) {
  138. zend_hash_get_current_key_ex(&shm->blocks, (void *) &ptr, NULL, NULL, 0, &pos);
  139. if ((char *) p >= *ptr && (char *) p < *ptr + *psize) {
  140. return 1;
  141. }
  142. zend_hash_move_forward_ex(&shm->blocks, &pos);
  143. }
  144. #endif
  145. return 0;
  146. }
  147. /* }}} */
  148. static XC_SHM_IS_READONLY(xc_malloc_is_readonly) /* {{{ */
  149. {
  150. return 0;
  151. }
  152. /* }}} */
  153. static XC_SHM_TO_READWRITE(xc_malloc_to_readwrite) /* {{{ */
  154. {
  155. return p;
  156. }
  157. /* }}} */
  158. static XC_SHM_TO_READONLY(xc_malloc_to_readonly) /* {{{ */
  159. {
  160. return p;
  161. }
  162. /* }}} */
  163. static XC_SHM_DESTROY(xc_malloc_destroy) /* {{{ */
  164. {
  165. #ifndef TEST
  166. zend_hash_destroy(&shm->blocks);
  167. #endif
  168. free(shm);
  169. return;
  170. }
  171. /* }}} */
  172. static XC_SHM_INIT(xc_malloc_init) /* {{{ */
  173. {
  174. xc_shm_t *shm;
  175. CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
  176. shm->size = size;
  177. #ifndef TEST
  178. zend_hash_init(&shm->blocks, 64, NULL, NULL, 1);
  179. #endif
  180. return shm;
  181. err:
  182. return NULL;
  183. }
  184. /* }}} */
  185. static XC_SHM_MEMINIT(xc_malloc_meminit) /* {{{ */
  186. {
  187. void *mem;
  188. if (shm->memoffset + size > shm->size) {
  189. #ifndef TEST
  190. zend_error(E_ERROR, "XCache: internal error at %s#%d", __FILE__, __LINE__);
  191. #endif
  192. return NULL;
  193. }
  194. shm->memoffset += size;
  195. CHECK(mem = calloc(1, size), "mem OOM");
  196. return mem;
  197. err:
  198. return NULL;
  199. }
  200. /* }}} */
  201. static XC_SHM_MEMDESTROY(xc_malloc_memdestroy) /* {{{ */
  202. {
  203. free(mem);
  204. }
  205. /* }}} */
  206. static xc_allocator_vtable_t xc_allocator_malloc_vtable = XC_ALLOCATOR_VTABLE(allocator_malloc);
  207. #ifndef TEST
  208. static xc_shm_handlers_t xc_shm_malloc_handlers = XC_SHM_HANDLERS(malloc);
  209. #endif
  210. void xc_allocator_malloc_register() /* {{{ */
  211. {
  212. if (xc_allocator_register("malloc", &xc_allocator_malloc_vtable) == 0) {
  213. #ifndef TEST
  214. zend_error(E_ERROR, "XCache: failed to register malloc mem_scheme");
  215. #endif
  216. }
  217. }
  218. /* }}} */
  219. #ifndef TEST
  220. void xc_shm_malloc_register() /* {{{ */
  221. {
  222. if (xc_shm_scheme_register("malloc", &xc_shm_malloc_handlers) == 0) {
  223. zend_error(E_ERROR, "XCache: failed to register malloc shm_scheme");
  224. }
  225. }
  226. /* }}} */
  227. #endif