mysqlnd_block_alloc.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2006-2016 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: Georg Richter <georg@mysql.com> |
  16. | Andrey Hristov <andrey@mysql.com> |
  17. | Ulf Wendel <uwendel@mysql.com> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id$ */
  21. #include "php.h"
  22. #include "mysqlnd.h"
  23. #include "mysqlnd_block_alloc.h"
  24. #include "mysqlnd_debug.h"
  25. #include "mysqlnd_priv.h"
  26. /* {{{ mysqlnd_mempool_free_chunk */
  27. static void
  28. mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk TSRMLS_DC)
  29. {
  30. MYSQLND_MEMORY_POOL * pool = chunk->pool;
  31. DBG_ENTER("mysqlnd_mempool_free_chunk");
  32. if (chunk->from_pool) {
  33. /* Try to back-off and guess if this is the last block allocated */
  34. if (chunk->ptr == (pool->arena + (pool->arena_size - pool->free_size - chunk->size))) {
  35. /*
  36. This was the last allocation. Lucky us, we can free
  37. a bit of memory from the pool. Next time we will return from the same ptr.
  38. */
  39. pool->free_size += chunk->size;
  40. }
  41. pool->refcount--;
  42. } else {
  43. mnd_free(chunk->ptr);
  44. }
  45. mnd_free(chunk);
  46. DBG_VOID_RETURN;
  47. }
  48. /* }}} */
  49. /* {{{ mysqlnd_mempool_resize_chunk */
  50. static enum_func_status
  51. mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, unsigned int size TSRMLS_DC)
  52. {
  53. DBG_ENTER("mysqlnd_mempool_resize_chunk");
  54. if (chunk->from_pool) {
  55. MYSQLND_MEMORY_POOL * pool = chunk->pool;
  56. /* Try to back-off and guess if this is the last block allocated */
  57. if (chunk->ptr == (pool->arena + (pool->arena_size - pool->free_size - chunk->size))) {
  58. /*
  59. This was the last allocation. Lucky us, we can free
  60. a bit of memory from the pool. Next time we will return from the same ptr.
  61. */
  62. if ((chunk->size + pool->free_size) < size) {
  63. zend_uchar *new_ptr;
  64. new_ptr = mnd_malloc(size);
  65. if (!new_ptr) {
  66. DBG_RETURN(FAIL);
  67. }
  68. memcpy(new_ptr, chunk->ptr, chunk->size);
  69. chunk->ptr = new_ptr;
  70. pool->free_size += chunk->size;
  71. chunk->size = size;
  72. chunk->pool = NULL; /* now we have no pool memory */
  73. pool->refcount--;
  74. } else {
  75. /* If the chunk is > than asked size then free_memory increases, otherwise decreases*/
  76. pool->free_size += (chunk->size - size);
  77. }
  78. } else {
  79. /* Not last chunk, if the user asks for less, give it to him */
  80. if (chunk->size >= size) {
  81. ; /* nop */
  82. } else {
  83. zend_uchar *new_ptr;
  84. new_ptr = mnd_malloc(size);
  85. if (!new_ptr) {
  86. DBG_RETURN(FAIL);
  87. }
  88. memcpy(new_ptr, chunk->ptr, chunk->size);
  89. chunk->ptr = new_ptr;
  90. chunk->size = size;
  91. chunk->pool = NULL; /* now we have non-pool memory */
  92. pool->refcount--;
  93. }
  94. }
  95. } else {
  96. zend_uchar *new_ptr = mnd_realloc(chunk->ptr, size);
  97. if (!new_ptr) {
  98. DBG_RETURN(FAIL);
  99. }
  100. chunk->ptr = new_ptr;
  101. }
  102. DBG_RETURN(PASS);
  103. }
  104. /* }}} */
  105. /* {{{ mysqlnd_mempool_get_chunk */
  106. static
  107. MYSQLND_MEMORY_POOL_CHUNK * mysqlnd_mempool_get_chunk(MYSQLND_MEMORY_POOL * pool, unsigned int size TSRMLS_DC)
  108. {
  109. MYSQLND_MEMORY_POOL_CHUNK *chunk = NULL;
  110. DBG_ENTER("mysqlnd_mempool_get_chunk");
  111. chunk = mnd_malloc(sizeof(MYSQLND_MEMORY_POOL_CHUNK));
  112. if (chunk) {
  113. chunk->free_chunk = mysqlnd_mempool_free_chunk;
  114. chunk->resize_chunk = mysqlnd_mempool_resize_chunk;
  115. chunk->size = size;
  116. /*
  117. Should not go over MYSQLND_MAX_PACKET_SIZE, since we
  118. expect non-arena memory in mysqlnd_wireprotocol.c . We
  119. realloc the non-arena memory.
  120. */
  121. chunk->pool = pool;
  122. if (size > pool->free_size) {
  123. chunk->from_pool = FALSE;
  124. chunk->ptr = mnd_malloc(size);
  125. if (!chunk->ptr) {
  126. chunk->free_chunk(chunk TSRMLS_CC);
  127. chunk = NULL;
  128. }
  129. } else {
  130. chunk->from_pool = TRUE;
  131. ++pool->refcount;
  132. chunk->ptr = pool->arena + (pool->arena_size - pool->free_size);
  133. /* Last step, update free_size */
  134. pool->free_size -= size;
  135. }
  136. }
  137. DBG_RETURN(chunk);
  138. }
  139. /* }}} */
  140. /* {{{ mysqlnd_mempool_create */
  141. PHPAPI MYSQLND_MEMORY_POOL *
  142. mysqlnd_mempool_create(size_t arena_size TSRMLS_DC)
  143. {
  144. /* We calloc, because we free(). We don't mnd_calloc() for a reason. */
  145. MYSQLND_MEMORY_POOL * ret = mnd_calloc(1, sizeof(MYSQLND_MEMORY_POOL));
  146. DBG_ENTER("mysqlnd_mempool_create");
  147. if (ret) {
  148. ret->get_chunk = mysqlnd_mempool_get_chunk;
  149. ret->free_size = ret->arena_size = arena_size ? arena_size : 0;
  150. ret->refcount = 0;
  151. /* OOM ? */
  152. ret->arena = mnd_malloc(ret->arena_size);
  153. if (!ret->arena) {
  154. mysqlnd_mempool_destroy(ret TSRMLS_CC);
  155. ret = NULL;
  156. }
  157. }
  158. DBG_RETURN(ret);
  159. }
  160. /* }}} */
  161. /* {{{ mysqlnd_mempool_destroy */
  162. PHPAPI void
  163. mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL * pool TSRMLS_DC)
  164. {
  165. DBG_ENTER("mysqlnd_mempool_destroy");
  166. /* mnd_free will reference LOCK_access and might crash, depending on the caller...*/
  167. mnd_free(pool->arena);
  168. mnd_free(pool);
  169. DBG_VOID_RETURN;
  170. }
  171. /* }}} */
  172. /*
  173. * Local variables:
  174. * tab-width: 4
  175. * c-basic-offset: 4
  176. * End:
  177. * vim600: noet sw=4 ts=4 fdm=marker
  178. * vim<600: noet sw=4 ts=4
  179. */