PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/php-src/ext/apc/apc_pool.c

https://gitlab.com/0072016/appengine-php
C | 509 lines | 299 code | 104 blank | 106 comment | 39 complexity | 8c38f545890cbe34b064dac7bac2d571 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | APC |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2006-2011 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
  16. +----------------------------------------------------------------------+
  17. This software was contributed to PHP by Yahoo! Inc. in 2008.
  18. Future revisions and derivatives of this source code must acknowledge
  19. Yahoo! Inc. as the original contributor of this module by
  20. leaving this note intact in the source code.
  21. All other licensing and usage conditions are those of the PHP Group.
  22. */
  23. /* $Id: apc_pool.c 327069 2012-08-12 08:56:55Z laruence $ */
  24. #include "apc_pool.h"
  25. #include <assert.h>
  26. #ifdef HAVE_VALGRIND_MEMCHECK_H
  27. #include <valgrind/memcheck.h>
  28. #endif
  29. /* {{{ forward references */
  30. static apc_pool* apc_unpool_create(apc_pool_type type, apc_malloc_t, apc_free_t, apc_protect_t, apc_unprotect_t TSRMLS_DC);
  31. static apc_pool* apc_realpool_create(apc_pool_type type, apc_malloc_t, apc_free_t, apc_protect_t, apc_unprotect_t TSRMLS_DC);
  32. /* }}} */
  33. /* {{{ apc_pool_create */
  34. apc_pool* apc_pool_create(apc_pool_type pool_type,
  35. apc_malloc_t allocate,
  36. apc_free_t deallocate,
  37. apc_protect_t protect,
  38. apc_unprotect_t unprotect
  39. TSRMLS_DC)
  40. {
  41. if(pool_type == APC_UNPOOL) {
  42. return apc_unpool_create(pool_type, allocate, deallocate,
  43. protect, unprotect TSRMLS_CC);
  44. }
  45. return apc_realpool_create(pool_type, allocate, deallocate,
  46. protect, unprotect TSRMLS_CC);
  47. }
  48. /* }}} */
  49. /* {{{ apc_pool_destroy */
  50. void apc_pool_destroy(apc_pool *pool TSRMLS_DC)
  51. {
  52. apc_free_t deallocate = pool->deallocate;
  53. apc_pcleanup_t cleanup = pool->cleanup;
  54. cleanup(pool TSRMLS_CC);
  55. deallocate(pool TSRMLS_CC);
  56. }
  57. /* }}} */
  58. /* {{{ apc_unpool implementation */
  59. typedef struct _apc_unpool apc_unpool;
  60. struct _apc_unpool {
  61. apc_pool parent;
  62. /* apc_unpool is a lie! */
  63. };
  64. static void* apc_unpool_alloc(apc_pool* pool, size_t size TSRMLS_DC)
  65. {
  66. apc_unpool *upool = (apc_unpool*)pool;
  67. apc_malloc_t allocate = upool->parent.allocate;
  68. upool->parent.size += size;
  69. upool->parent.used += size;
  70. return allocate(size TSRMLS_CC);
  71. }
  72. static void apc_unpool_free(apc_pool* pool, void *ptr TSRMLS_DC)
  73. {
  74. apc_unpool *upool = (apc_unpool*) pool;
  75. apc_free_t deallocate = upool->parent.deallocate;
  76. deallocate(ptr TSRMLS_CC);
  77. }
  78. static void apc_unpool_cleanup(apc_pool* pool TSRMLS_DC)
  79. {
  80. }
  81. static apc_pool* apc_unpool_create(apc_pool_type type,
  82. apc_malloc_t allocate, apc_free_t deallocate,
  83. apc_protect_t protect, apc_unprotect_t unprotect
  84. TSRMLS_DC)
  85. {
  86. apc_unpool* upool = allocate(sizeof(apc_unpool) TSRMLS_CC);
  87. if (!upool) {
  88. return NULL;
  89. }
  90. upool->parent.type = type;
  91. upool->parent.allocate = allocate;
  92. upool->parent.deallocate = deallocate;
  93. upool->parent.protect = protect;
  94. upool->parent.unprotect = unprotect;
  95. upool->parent.palloc = apc_unpool_alloc;
  96. upool->parent.pfree = apc_unpool_free;
  97. upool->parent.cleanup = apc_unpool_cleanup;
  98. upool->parent.used = 0;
  99. upool->parent.size = 0;
  100. return &(upool->parent);
  101. }
  102. /* }}} */
  103. /*{{{ apc_realpool implementation */
  104. /* {{{ typedefs */
  105. typedef struct _pool_block
  106. {
  107. size_t avail;
  108. size_t capacity;
  109. unsigned char *mark;
  110. struct _pool_block *next;
  111. unsigned :0; /* this should align to word */
  112. /* data comes here */
  113. }pool_block;
  114. /*
  115. parts in ? are optional and turned on for fun, memory loss,
  116. and for something else that I forgot about ... ah, debugging
  117. |--------> data[] |<-- non word boundary (too)
  118. +-------------+--------------+-----------+-------------+-------------->>>
  119. | pool_block | ?sizeinfo<1> | block<1> | ?redzone<1> | ?sizeinfo<2>
  120. | | (size_t) | | padded left |
  121. +-------------+--------------+-----------+-------------+-------------->>>
  122. */
  123. typedef struct _apc_realpool apc_realpool;
  124. struct _apc_realpool
  125. {
  126. struct _apc_pool parent;
  127. size_t dsize;
  128. void *owner;
  129. unsigned long count;
  130. pool_block *head;
  131. pool_block first;
  132. };
  133. /* }}} */
  134. /* {{{ redzone code */
  135. static const unsigned char decaff[] = {
  136. 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad,
  137. 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad,
  138. 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad,
  139. 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad
  140. };
  141. /* a redzone is at least 4 (0xde,0xca,0xc0,0xff) bytes */
  142. #define REDZONE_SIZE(size) \
  143. ((ALIGNWORD((size)) > ((size) + 4)) ? \
  144. (ALIGNWORD((size)) - (size)) : /* does not change realsize */\
  145. ALIGNWORD((size)) - (size) + ALIGNWORD((sizeof(char)))) /* adds 1 word to realsize */
  146. #define SIZEINFO_SIZE ALIGNWORD(sizeof(size_t))
  147. #define MARK_REDZONE(block, redsize) do {\
  148. memcpy(block, decaff, redsize );\
  149. } while(0)
  150. #define CHECK_REDZONE(block, redsize) (memcmp(block, decaff, redsize) == 0)
  151. /* }}} */
  152. #define INIT_POOL_BLOCK(rpool, entry, size) do {\
  153. (entry)->avail = (entry)->capacity = (size);\
  154. (entry)->mark = ((unsigned char*)(entry)) + ALIGNWORD(sizeof(pool_block));\
  155. (entry)->next = (rpool)->head;\
  156. (rpool)->head = (entry);\
  157. } while(0)
  158. /* {{{ create_pool_block */
  159. static pool_block* create_pool_block(apc_realpool *rpool, size_t size TSRMLS_DC)
  160. {
  161. apc_malloc_t allocate = rpool->parent.allocate;
  162. size_t realsize = sizeof(pool_block) + ALIGNWORD(size);
  163. pool_block* entry = allocate(realsize TSRMLS_CC);
  164. if (!entry) {
  165. return NULL;
  166. }
  167. INIT_POOL_BLOCK(rpool, entry, size);
  168. rpool->parent.size += realsize;
  169. rpool->count++;
  170. return entry;
  171. }
  172. /* }}} */
  173. /* {{{ apc_realpool_alloc */
  174. static void* apc_realpool_alloc(apc_pool *pool, size_t size TSRMLS_DC)
  175. {
  176. apc_realpool *rpool = (apc_realpool*)pool;
  177. unsigned char *p = NULL;
  178. size_t realsize = ALIGNWORD(size);
  179. size_t poolsize;
  180. unsigned char *redzone = NULL;
  181. size_t redsize = 0;
  182. size_t *sizeinfo= NULL;
  183. pool_block *entry = NULL;
  184. unsigned long i;
  185. if(APC_POOL_HAS_REDZONES(pool)) {
  186. redsize = REDZONE_SIZE(size); /* redsize might be re-using word size padding */
  187. realsize = size + redsize; /* recalculating realsize */
  188. } else {
  189. redsize = realsize - size; /* use padding space */
  190. }
  191. if(APC_POOL_HAS_SIZEINFO(pool)) {
  192. realsize += ALIGNWORD(sizeof(size_t));
  193. }
  194. /* minimize look-back, a value of 8 seems to give similar fill-ratios (+2%)
  195. * as looping through the entire list. And much faster in allocations. */
  196. for(entry = rpool->head, i = 0; entry != NULL && (i < 8); entry = entry->next, i++) {
  197. if(entry->avail >= realsize) {
  198. goto found;
  199. }
  200. }
  201. /* upgrade the pool type to reduce overhead */
  202. if(rpool->count > 4 && rpool->dsize < 4096) {
  203. rpool->dsize = 4096;
  204. } else if(rpool->count > 8 && rpool->dsize < 8192) {
  205. rpool->dsize = 8192;
  206. }
  207. poolsize = ALIGNSIZE(realsize, rpool->dsize);
  208. entry = create_pool_block(rpool, poolsize TSRMLS_CC);
  209. if(!entry) {
  210. return NULL;
  211. }
  212. found:
  213. p = entry->mark;
  214. if(APC_POOL_HAS_SIZEINFO(pool)) {
  215. sizeinfo = (size_t*)p;
  216. p += SIZEINFO_SIZE;
  217. *sizeinfo = size;
  218. }
  219. redzone = p + size;
  220. if(APC_POOL_HAS_REDZONES(pool)) {
  221. MARK_REDZONE(redzone, redsize);
  222. }
  223. #ifdef VALGRIND_MAKE_MEM_NOACCESS
  224. if(redsize != 0) {
  225. VALGRIND_MAKE_MEM_NOACCESS(redzone, redsize);
  226. }
  227. #endif
  228. entry->avail -= realsize;
  229. entry->mark += realsize;
  230. pool->used += realsize;
  231. #ifdef VALGRIND_MAKE_MEM_UNDEFINED
  232. /* need to write before reading data off this */
  233. VALGRIND_MAKE_MEM_UNDEFINED(p, size);
  234. #endif
  235. return (void*)p;
  236. }
  237. /* }}} */
  238. /* {{{ apc_realpool_check_integrity */
  239. /*
  240. * Checking integrity at runtime, does an
  241. * overwrite check only when the sizeinfo
  242. * is set.
  243. *
  244. * Marked as used in gcc, so that this function
  245. * is accessible from gdb, eventhough it is never
  246. * used in code in non-debug builds.
  247. */
  248. static APC_USED int apc_realpool_check_integrity(apc_realpool *rpool)
  249. {
  250. apc_pool *pool = &(rpool->parent);
  251. pool_block *entry;
  252. size_t *sizeinfo = NULL;
  253. unsigned char *start;
  254. size_t realsize;
  255. unsigned char *redzone;
  256. size_t redsize;
  257. for(entry = rpool->head; entry != NULL; entry = entry->next) {
  258. start = (unsigned char *)entry + ALIGNWORD(sizeof(pool_block));
  259. if((entry->mark - start) != (entry->capacity - entry->avail)) {
  260. return 0;
  261. }
  262. }
  263. if(!APC_POOL_HAS_REDZONES(pool) ||
  264. !APC_POOL_HAS_SIZEINFO(pool)) {
  265. (void)pool; /* remove unused warning */
  266. return 1;
  267. }
  268. for(entry = rpool->head; entry != NULL; entry = entry->next) {
  269. start = (unsigned char *)entry + ALIGNWORD(sizeof(pool_block));
  270. while(start < entry->mark) {
  271. sizeinfo = (size_t*)start;
  272. /* redzone starts where real data ends, in a non-word boundary
  273. * redsize is at least 4 bytes + whatever's needed to make it
  274. * to another word boundary.
  275. */
  276. redzone = start + SIZEINFO_SIZE + (*sizeinfo);
  277. redsize = REDZONE_SIZE(*sizeinfo);
  278. #ifdef VALGRIND_MAKE_MEM_DEFINED
  279. VALGRIND_MAKE_MEM_DEFINED(redzone, redsize);
  280. #endif
  281. if(!CHECK_REDZONE(redzone, redsize))
  282. {
  283. /*
  284. fprintf(stderr, "Redzone check failed for %p\n",
  285. start + ALIGNWORD(sizeof(size_t)));*/
  286. return 0;
  287. }
  288. #ifdef VALGRIND_MAKE_MEM_NOACCESS
  289. VALGRIND_MAKE_MEM_NOACCESS(redzone, redsize);
  290. #endif
  291. realsize = SIZEINFO_SIZE + *sizeinfo + redsize;
  292. start += realsize;
  293. }
  294. }
  295. return 1;
  296. }
  297. /* }}} */
  298. /* {{{ apc_realpool_free */
  299. /*
  300. * free does not do anything other than
  301. * check for redzone values when free'ing
  302. * data areas.
  303. */
  304. static void apc_realpool_free(apc_pool *pool, void *p TSRMLS_DC)
  305. {
  306. }
  307. /* }}} */
  308. /* {{{ apc_realpool_cleanup */
  309. static void apc_realpool_cleanup(apc_pool *pool TSRMLS_DC)
  310. {
  311. pool_block *entry;
  312. pool_block *tmp;
  313. apc_realpool *rpool = (apc_realpool*)pool;
  314. apc_free_t deallocate = pool->deallocate;
  315. assert(apc_realpool_check_integrity(rpool)!=0);
  316. entry = rpool->head;
  317. while(entry->next != NULL) {
  318. tmp = entry->next;
  319. deallocate(entry TSRMLS_CC);
  320. entry = tmp;
  321. }
  322. }
  323. /* }}} */
  324. /* {{{ apc_realpool_create */
  325. static apc_pool* apc_realpool_create(apc_pool_type type, apc_malloc_t allocate, apc_free_t deallocate,
  326. apc_protect_t protect, apc_unprotect_t unprotect
  327. TSRMLS_DC)
  328. {
  329. size_t dsize = 0;
  330. apc_realpool *rpool;
  331. switch(type & APC_POOL_SIZE_MASK) {
  332. case APC_SMALL_POOL:
  333. dsize = 512;
  334. break;
  335. case APC_LARGE_POOL:
  336. dsize = 8192;
  337. break;
  338. case APC_MEDIUM_POOL:
  339. dsize = 4096;
  340. break;
  341. default:
  342. return NULL;
  343. }
  344. rpool = (apc_realpool*)allocate((sizeof(apc_realpool) + ALIGNWORD(dsize)) TSRMLS_CC);
  345. if(!rpool) {
  346. return NULL;
  347. }
  348. rpool->parent.type = type;
  349. rpool->parent.allocate = allocate;
  350. rpool->parent.deallocate = deallocate;
  351. rpool->parent.size = sizeof(apc_realpool) + ALIGNWORD(dsize);
  352. rpool->parent.palloc = apc_realpool_alloc;
  353. rpool->parent.pfree = apc_realpool_free;
  354. rpool->parent.protect = protect;
  355. rpool->parent.unprotect = unprotect;
  356. rpool->parent.cleanup = apc_realpool_cleanup;
  357. rpool->dsize = dsize;
  358. rpool->head = NULL;
  359. rpool->count = 0;
  360. INIT_POOL_BLOCK(rpool, &(rpool->first), dsize);
  361. return &(rpool->parent);
  362. }
  363. /* }}} */
  364. /* }}} */
  365. /* {{{ apc_pool_init */
  366. void apc_pool_init()
  367. {
  368. /* put all ye sanity checks here */
  369. assert(sizeof(decaff) > REDZONE_SIZE(ALIGNWORD(sizeof(char))));
  370. assert(sizeof(pool_block) == ALIGNWORD(sizeof(pool_block)));
  371. #if APC_POOL_DEBUG
  372. assert((APC_POOL_SIZE_MASK & (APC_POOL_SIZEINFO | APC_POOL_REDZONES)) == 0);
  373. #endif
  374. }
  375. /* }}} */
  376. /* {{{ apc_pstrdup */
  377. void* APC_ALLOC apc_pstrdup(const char* s, apc_pool* pool TSRMLS_DC)
  378. {
  379. return s != NULL ? apc_pmemcpy(s, (strlen(s) + 1), pool TSRMLS_CC) : NULL;
  380. }
  381. /* }}} */
  382. /* {{{ apc_pmemcpy */
  383. void* APC_ALLOC apc_pmemcpy(const void* p, size_t n, apc_pool* pool TSRMLS_DC)
  384. {
  385. void* q;
  386. if (p != NULL && (q = apc_pool_alloc(pool, n)) != NULL) {
  387. memcpy(q, p, n);
  388. return q;
  389. }
  390. return NULL;
  391. }
  392. /* }}} */
  393. /*
  394. * Local variables:
  395. * tab-width: 4
  396. * c-basic-offset: 4
  397. * End:
  398. * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
  399. * vim<600: expandtab sw=4 ts=4 sts=4
  400. */