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