Back to index

php5  5.3.10
mysqlnd_block_alloc.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 2006-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Georg Richter <georg@mysql.com>                             |
00016   |          Andrey Hristov <andrey@mysql.com>                           |
00017   |          Ulf Wendel <uwendel@mysql.com>                              |
00018   +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: mysqlnd_block_alloc.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #include "php.h"
00024 #include "mysqlnd.h"
00025 #include "mysqlnd_block_alloc.h"
00026 #include "mysqlnd_debug.h"
00027 #include "mysqlnd_priv.h"
00028 
00029 
00030 /* {{{ mysqlnd_mempool_free_chunk */
00031 static void
00032 mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk TSRMLS_DC)
00033 {
00034        MYSQLND_MEMORY_POOL * pool = chunk->pool;
00035        DBG_ENTER("mysqlnd_mempool_free_chunk");
00036        if (chunk->from_pool) {
00037               /* Try to back-off and guess if this is the last block allocated */
00038               if (chunk->ptr == (pool->arena + (pool->arena_size - pool->free_size - chunk->size))) {
00039                      /*
00040                             This was the last allocation. Lucky us, we can free
00041                             a bit of memory from the pool. Next time we will return from the same ptr.
00042                      */
00043                      pool->free_size += chunk->size;
00044               }
00045               pool->refcount--;
00046        } else {
00047               mnd_free(chunk->ptr);
00048        }
00049        mnd_free(chunk);
00050        DBG_VOID_RETURN;
00051 }
00052 /* }}} */
00053 
00054 
00055 /* {{{ mysqlnd_mempool_resize_chunk */
00056 static enum_func_status
00057 mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, unsigned int size TSRMLS_DC)
00058 {
00059        DBG_ENTER("mysqlnd_mempool_resize_chunk");
00060        if (chunk->from_pool) {
00061               MYSQLND_MEMORY_POOL * pool = chunk->pool;
00062               /* Try to back-off and guess if this is the last block allocated */
00063               if (chunk->ptr == (pool->arena + (pool->arena_size - pool->free_size - chunk->size))) {
00064                      /*
00065                             This was the last allocation. Lucky us, we can free
00066                             a bit of memory from the pool. Next time we will return from the same ptr.
00067                      */
00068                      if ((chunk->size + pool->free_size) < size) {
00069                             zend_uchar *new_ptr;
00070                             new_ptr = mnd_malloc(size);
00071                             if (!new_ptr) {
00072                                    DBG_RETURN(FAIL);
00073                             }
00074                             memcpy(new_ptr, chunk->ptr, chunk->size);
00075                             chunk->ptr = new_ptr;
00076                             pool->free_size += chunk->size;
00077                             chunk->size = size;
00078                             chunk->pool = NULL; /* now we have no pool memory */
00079                             pool->refcount--;
00080                      } else {
00081                             /* If the chunk is > than asked size then free_memory increases, otherwise decreases*/
00082                             pool->free_size += (chunk->size - size);
00083                      }
00084               } else {
00085                      /* Not last chunk, if the user asks for less, give it to him */
00086                      if (chunk->size >= size) {
00087                             ; /* nop */
00088                      } else {
00089                             zend_uchar *new_ptr;
00090                             new_ptr = mnd_malloc(size);
00091                             if (!new_ptr) {
00092                                    DBG_RETURN(FAIL);
00093                             }
00094                             memcpy(new_ptr, chunk->ptr, chunk->size);
00095                             chunk->ptr = new_ptr;
00096                             chunk->size = size;
00097                             chunk->pool = NULL; /* now we have non-pool memory */
00098                             pool->refcount--;
00099                      }
00100               }
00101        } else {
00102               zend_uchar *new_ptr = mnd_realloc(chunk->ptr, size);
00103               if (!new_ptr) {
00104                      DBG_RETURN(FAIL);
00105               }
00106               chunk->ptr = new_ptr;
00107        }
00108        DBG_RETURN(PASS);
00109 }
00110 /* }}} */
00111 
00112 
00113 /* {{{ mysqlnd_mempool_get_chunk */
00114 static
00115 MYSQLND_MEMORY_POOL_CHUNK * mysqlnd_mempool_get_chunk(MYSQLND_MEMORY_POOL * pool, unsigned int size TSRMLS_DC)
00116 {
00117        MYSQLND_MEMORY_POOL_CHUNK *chunk = NULL;
00118        DBG_ENTER("mysqlnd_mempool_get_chunk");
00119 
00120        chunk = mnd_malloc(sizeof(MYSQLND_MEMORY_POOL_CHUNK));
00121        if (chunk) {
00122               chunk->free_chunk = mysqlnd_mempool_free_chunk;
00123               chunk->resize_chunk = mysqlnd_mempool_resize_chunk;
00124               chunk->size = size;
00125               /*
00126                 Should not go over MYSQLND_MAX_PACKET_SIZE, since we
00127                 expect non-arena memory in mysqlnd_wireprotocol.c . We
00128                 realloc the non-arena memory.
00129               */
00130               chunk->pool = pool;
00131               if (size > pool->free_size) {
00132                      chunk->from_pool = FALSE;
00133                      chunk->ptr = mnd_malloc(size);
00134                      if (!chunk->ptr) {
00135                             chunk->free_chunk(chunk TSRMLS_CC);
00136                             chunk = NULL;
00137                      }
00138               } else {
00139                      chunk->from_pool = TRUE;
00140                      ++pool->refcount;
00141                      chunk->ptr = pool->arena + (pool->arena_size - pool->free_size);
00142                      /* Last step, update free_size */
00143                      pool->free_size -= size;
00144               }
00145        }
00146        DBG_RETURN(chunk);
00147 }
00148 /* }}} */
00149 
00150 
00151 /* {{{ mysqlnd_mempool_create */
00152 PHPAPI MYSQLND_MEMORY_POOL *
00153 mysqlnd_mempool_create(size_t arena_size TSRMLS_DC)
00154 {
00155        /* We calloc, because we free(). We don't mnd_calloc()  for a reason. */
00156        MYSQLND_MEMORY_POOL * ret = mnd_calloc(1, sizeof(MYSQLND_MEMORY_POOL));
00157        DBG_ENTER("mysqlnd_mempool_create");
00158        if (ret) {
00159               ret->get_chunk = mysqlnd_mempool_get_chunk;
00160               ret->free_size = ret->arena_size = arena_size ? arena_size : 0;
00161               ret->refcount = 0;
00162               /* OOM ? */
00163               ret->arena = mnd_malloc(ret->arena_size);
00164               if (!ret->arena) {
00165                      mysqlnd_mempool_destroy(ret TSRMLS_CC);
00166                      ret = NULL;
00167               }
00168        }
00169        DBG_RETURN(ret);
00170 }
00171 /* }}} */
00172 
00173 
00174 /* {{{ mysqlnd_mempool_destroy */
00175 PHPAPI void
00176 mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL * pool TSRMLS_DC)
00177 {
00178        DBG_ENTER("mysqlnd_mempool_destroy");
00179        /* mnd_free will reference LOCK_access and might crash, depending on the caller...*/
00180        mnd_free(pool->arena);
00181        mnd_free(pool);
00182        DBG_VOID_RETURN;
00183 }
00184 /* }}} */
00185 
00186 
00187 /*
00188  * Local variables:
00189  * tab-width: 4
00190  * c-basic-offset: 4
00191  * End:
00192  * vim600: noet sw=4 ts=4 fdm=marker
00193  * vim<600: noet sw=4 ts=4
00194  */