Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Fast Pool Allocator
0003  *
0004  * @file fpalloc.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 
0035 /*---------------------------Includes-----------------------------------*/
0036 #include <ndrx_config.h>
0037 #include <string.h>
0038 #include <stdio.h>
0039 #include <stdlib.h>
0040 #include <pthread.h>
0041 #include <sys_primitives.h> /**< spin locks for MacOS */
0042 #include <ndrstandard.h>
0043 #include <fpalloc.h>
0044 #include <thlock.h>
0045 #include <errno.h>
0046 #include <nstdutil.h>
0047 #include <userlog.h>
0048 #include <nstd_int.h>
0049 
0050 #include "ndebug.h"
0051 /*---------------------------Externs------------------------------------*/
0052 /*---------------------------Macros-------------------------------------*/
0053 
0054 /* states: */            
0055 #define NDRX_FP_GETSIZE         1
0056 #define NDRX_FP_GETMODE         2
0057 #define NDRX_FP_USEMALLOC       3
0058 #define NDRX_FP_USENUMBL        4
0059 
0060 
0061 /* debug of FPA */
0062 #define NDRX_FPDEBUG(fmt, ...)
0063 /*#define NDRX_FPDEBUG(fmt, ...) NDRX_LOG(log_debug, fmt, ##__VA_ARGS__)*/
0064 
0065 
0066 /*---------------------------Enums--------------------------------------*/
0067 /*---------------------------Typedefs-----------------------------------*/
0068 /*---------------------------Globals------------------------------------*/
0069 
0070 /**
0071  * List of malloc pools with different sizes and min/max settings
0072  */
0073 exprivate ndrx_fpapool_t M_fpa_pools[NDRX_FPA_MAX] =
0074 {  
0075     /* size                 flags   */
0076      {NDRX_FPA_0_SIZE,       NDRX_FPNOFLAG, NDRX_FPA_0_DNUM}      /* 0 */
0077     ,{NDRX_FPA_1_SIZE,       NDRX_FPNOFLAG, NDRX_FPA_1_DNUM}      /* 1 */
0078     ,{NDRX_FPA_2_SIZE,       NDRX_FPNOFLAG, NDRX_FPA_2_DNUM}      /* 2 */
0079     ,{NDRX_FPA_3_SIZE,       NDRX_FPNOFLAG, NDRX_FPA_3_DNUM}      /* 3 */
0080     ,{NDRX_FPA_4_SIZE,       NDRX_FPNOFLAG, NDRX_FPA_4_DNUM}      /* 4 */
0081     ,{NDRX_FPA_5_SIZE,       NDRX_FPNOFLAG, NDRX_FPA_5_DNUM}      /* 5 */
0082     ,{NDRX_FPA_SIZE_SYSBUF,  NDRX_FPSYSBUF, NDRX_FPA_SYSBUF_DNUM} /* 6 */
0083 };
0084 
0085 /*---------------------------Statics------------------------------------*/
0086 exprivate MUTEX_LOCKDECL(M_initlock);
0087 exprivate volatile int M_init_first = EXTRUE;   /**< had the init ?     */
0088 exprivate int M_malloc_all = EXFALSE;           /**< do sys malloc only */
0089 exprivate char *M_opts = NULL;                  /**< env options        */
0090 /*---------------------------Prototypes---------------------------------*/
0091 
0092 
0093 /**
0094  * return pool stats (not for prod use)
0095  * @param poolno pool number
0096  * @param stats p_stats stnapshoot of the pool
0097  */
0098 expublic void ndrx_fpstats(int poolno, ndrx_fpapool_t *p_stats)
0099 {
0100     /* lock the pool */
0101     NDRX_SPIN_LOCK_V(M_fpa_pools[poolno].spinlock);
0102     memcpy((char *)p_stats, (char *)&M_fpa_pools[poolno], sizeof(ndrx_fpapool_t));
0103     NDRX_SPIN_UNLOCK_V(M_fpa_pools[poolno].spinlock);
0104 }
0105 
0106 /**
0107  * This is thread safe way...
0108  */
0109 expublic void ndrx_fpuninit(void)
0110 {
0111     int i;
0112     volatile ndrx_fpablock_t *freebl;
0113     /* free up all allocated pages... */
0114     
0115     if (M_init_first)
0116     {
0117         /* nothing todo */
0118         return;
0119     }
0120     
0121     /* remove all blocks */
0122     for (i=0; i<N_DIM(M_fpa_pools); i++)
0123     {
0124         do
0125         {
0126             freebl = NULL;
0127             
0128             NDRX_SPIN_LOCK_V(M_fpa_pools[i].spinlock);
0129 
0130             freebl = M_fpa_pools[i].stack;
0131             
0132             if (NULL!=freebl)
0133             {
0134                 M_fpa_pools[i].stack = freebl->next;
0135             }
0136 
0137             NDRX_SPIN_UNLOCK_V(M_fpa_pools[i].spinlock);
0138             
0139             if (NULL!=freebl)
0140             {
0141                 NDRX_FREE((void *)freebl);
0142             }
0143             
0144         } 
0145         while (NULL!=freebl);
0146     }
0147     
0148     M_init_first=EXTRUE;
0149 }
0150 
0151 /**
0152  * Init the feedback allocator. This will parse CONF_NDRX_FPAOPTS env
0153  * variable, if provided.
0154  * @return EXSUCCEED/EXFAIL
0155  */
0156 exprivate int ndrx_fpinit(void)
0157 {
0158     int ret = EXSUCCEED;
0159     int i, state, blocksz, bnum, found, len, multiplier;
0160     char settings[1024];
0161     char *bconf, *bopt, *saveptr1, *saveptr2;
0162     /* load defaults */
0163     for (i=0; i<N_DIM(M_fpa_pools); i++)
0164     {
0165         M_fpa_pools[i].cur_blocks = 0;
0166         M_fpa_pools[i].stack = NULL;
0167         M_fpa_pools[i].allocs = 0;
0168         NDRX_SPIN_INIT_V(M_fpa_pools[i].spinlock);
0169     }
0170     
0171     /* setup the options if any... */
0172     M_opts=getenv(CONF_NDRX_FPAOPTS);
0173     
0174     if (NULL!=M_opts)
0175     {
0176         NDRX_FPDEBUG("Loading config: [%s]", M_opts);
0177         
0178         NDRX_STRCPY_SAFE(settings, M_opts);
0179         
0180         /* start parse. 
0181          * format:
0182          * [<D|S|KB>:{M|<MIN>{[:<MAX>]|[:<MAX>,<HITS>]}}][,..,[<D|S|KB>:{M|<MIN>{[:<MAX>]|[:<MAX>:<HITS>]}}]]
0183          * where:
0184          * 'D' - Defaults, change all allocation stacks
0185          * 'S' - System buffer 
0186          * 'KB' - Block size, currently const 1,2,4,5,16,32,64
0187          * 'M' - use system malloc
0188          * 'MIN' - min blocks in pool
0189          * 'MAX' - max blocks in pool
0190          * 'HITS' - number of gotten.
0191          * This will not remove any spaces, etc.... In case of parse failure,
0192          * ulog will be written and defaults will be used.
0193          */
0194         for (bconf=strtok_r(settings, ",", &saveptr1); NULL!=bconf; bconf=strtok_r(NULL, ",", &saveptr1))
0195         {   
0196             /* got block config, parse each */
0197             
0198             NDRX_FPDEBUG("Parsing block: [%s]", bconf);
0199             
0200             state = NDRX_FP_GETSIZE;
0201             bnum=EXFAIL;
0202             for (bopt=strtok_r(bconf, ":", &saveptr2); NULL!=bopt; bopt=strtok_r(NULL, ":", &saveptr2))
0203             {
0204                 NDRX_FPDEBUG("Parsing option: [%s]", bopt);
0205                 
0206                 switch (state)
0207                 {
0208                     case NDRX_FP_GETSIZE:
0209                         
0210                         if (0==strcmp(bopt, "D"))
0211                         {
0212                             blocksz = NDRX_FPA_SIZE_DEFAULT;
0213                         }
0214                         else if (0==strcmp(bopt, "S"))
0215                         {
0216                             blocksz = NDRX_FPA_SIZE_SYSBUF;
0217                         }
0218                         else
0219                         {
0220                             len = strlen(bopt);
0221                             multiplier=1;
0222                             
0223                             if (len > 0)
0224                             {
0225                                 if (bopt[len-1]=='K')
0226                                 {
0227                                     multiplier=1024;
0228                                     bopt[len-1]=EXEOS;
0229                                 }
0230                                 else if (bopt[len-1]<'0' || bopt[len-1]>'9')
0231                                 {
0232                                     userlog("%s: Invalid 'size' size multiplier "
0233                                             "[%c] for token [%s] in [%s] ", 
0234                                         CONF_NDRX_FPAOPTS, bopt[len-1], bopt, M_opts);
0235                                     EXFAIL_OUT(ret);
0236                                 }
0237                             }
0238                             
0239                             if (!ndrx_is_numberic(bopt))
0240                             {
0241                                 userlog("%s: Invalid 'size' token [%s] in [%s]", 
0242                                         CONF_NDRX_FPAOPTS, bopt, M_opts);
0243                                 EXFAIL_OUT(ret);
0244                             }
0245                             
0246                             blocksz = atoi(bopt)*multiplier;
0247                         }
0248                         
0249                         state = NDRX_FP_GETMODE;
0250                         break;
0251                     case NDRX_FP_GETMODE:
0252                         /* mode is either "M" or number (as min) */
0253                         if (0==strcmp(bopt, "M"))
0254                         {
0255                             NDRX_FPDEBUG("Use Malloc for size %d", blocksz);
0256                             
0257                             state = NDRX_FP_USEMALLOC;
0258                         }
0259                         else
0260                         {
0261                             if (!ndrx_is_numberic(bopt))
0262                             {
0263                                 userlog("%s: Invalid 'bnum' token [%s] in [%s]", 
0264                                         CONF_NDRX_FPAOPTS, bopt, M_opts);
0265                                 EXFAIL_OUT(ret);
0266                             }
0267                             
0268                             bnum = atoi(bopt);
0269                             
0270                             if (bnum < 1)
0271                             {
0272                                 userlog("%s: Invalid 'bnum' token (<1) [%s] in [%s]", 
0273                                         CONF_NDRX_FPAOPTS, bopt, M_opts);
0274                                 EXFAIL_OUT(ret);
0275                             }
0276                             
0277                             state=NDRX_FP_USENUMBL;
0278                             NDRX_FPDEBUG("bnum=%d", bnum);
0279                         }
0280                         break;
0281                     case NDRX_FP_USEMALLOC:
0282                         /* err ! not more settings! */
0283                         userlog("%s: Invalid argument for 'M' token [%s] in [%s]", 
0284                                         CONF_NDRX_FPAOPTS, bopt, M_opts);
0285                         EXFAIL_OUT(ret);
0286                         break;
0287                     case NDRX_FP_USENUMBL:
0288                         userlog("%s: Token not expected [%s] in [%s]", 
0289                                         CONF_NDRX_FPAOPTS, bopt, M_opts);
0290                         EXFAIL_OUT(ret);
0291                         break;
0292                 } /* case state */
0293             } /* for bopt */
0294             
0295             if (NDRX_FP_USEMALLOC > state)
0296             {
0297                 userlog("%s: Missing mode/min for block size %d in [%s]", 
0298                         CONF_NDRX_FPAOPTS, (int)blocksz, M_opts);
0299                 EXFAIL_OUT(ret);
0300             }
0301             
0302             /* not the best search, but only once for startup */
0303             found=EXFALSE;
0304             for (i=0; i<N_DIM(M_fpa_pools); i++)
0305             {
0306                 if (NDRX_FPA_SIZE_DEFAULT==blocksz || 
0307                         blocksz==M_fpa_pools[i].bsize)
0308                 {
0309                     /* Setup the block */
0310                     if (NDRX_FP_USEMALLOC==state)
0311                     {
0312                         M_fpa_pools[i].flags|=NDRX_FPNOPOOL;
0313                         NDRX_FPDEBUG("Pool %d flags set to: [%d]", 
0314                                 i, M_fpa_pools[i].flags);
0315                         found=EXTRUE;
0316                         
0317                         if (blocksz==M_fpa_pools[i].bsize)
0318                         {
0319                             break;
0320                         }
0321                     }
0322                     else 
0323                     {
0324                         if (EXFAIL!=bnum)
0325                         {
0326                             M_fpa_pools[i].num_blocks=bnum;
0327                         }
0328                         
0329                         found=EXTRUE;
0330                         
0331                         if (blocksz==M_fpa_pools[i].bsize)
0332                         {
0333                             break;
0334                         }
0335                     }
0336                 } /* check block size */
0337             } /* for stack */
0338             
0339             if (!found)
0340             {
0341                 userlog("%s: Block size %d not supported in [%s]", 
0342                         CONF_NDRX_FPAOPTS, blocksz, M_opts);
0343             }
0344         } /* for block config */
0345         
0346         /* check if all default -> set global flag to default malloc. */
0347         M_malloc_all = EXTRUE;
0348         for (i=0; i<N_DIM(M_fpa_pools); i++)
0349         {
0350             if (!(M_fpa_pools[i].flags & NDRX_FPNOPOOL))
0351             {
0352                 NDRX_FPDEBUG("Not malloc all due to [%d]", i);
0353                 M_malloc_all = EXFALSE;
0354                 break;
0355             }
0356         }
0357     } /* if has NDRX_FPAOPTS */
0358     
0359     M_init_first=EXFALSE;
0360     
0361 out:
0362                         
0363     if (EXSUCCEED!=ret)
0364     {
0365         errno=EINVAL;
0366     }
0367 
0368     return ret;
0369 }
0370 
0371 /*
0372  * Search for the target slot 
0373  */
0374 #define DO_BIN_SEARCH \
0375         do {\
0376             /* get the pool size */\
0377             int low=0, mid, high=NDRX_FPA_DYN_MAX-1;\
0378             \
0379             while(low <= high)\
0380             {\
0381                 mid = (low + high) / 2;\
0382                 \
0383                 if (M_fpa_pools[mid].bsize > size)\
0384                 {\
0385                     high = mid - 1;\
0386                 }\
0387                 else if (M_fpa_pools[mid].bsize < size)\
0388                 {\
0389                     low = mid + 1;\
0390                 }\
0391                 else\
0392                 {\
0393                     poolno = mid;\
0394                     break;\
0395                 }\
0396             }\
0397             \
0398             if (EXFAIL==poolno && high < NDRX_FPA_DYN_MAX-2)\
0399             {\
0400                 /* select next size */\
0401                 poolno = high+1;\
0402             }\
0403         }\
0404         while (0)
0405 
0406 /**
0407  * Malloc the memory block
0408  * @param size bytes to alloc
0409  * @param flags any special flag
0410  * @return for error = NULL  (errno set), or ptr to alloc'd block
0411  */
0412 expublic NDRX_API void *ndrx_fpmalloc(size_t size, int flags)
0413 {
0414     volatile ndrx_fpablock_t *addr = NULL;
0415     int poolno=EXFAIL;
0416     
0417     /* do the init. */
0418     if (NDRX_UNLIKELY(M_init_first))
0419     {
0420         MUTEX_LOCK_V(M_initlock);
0421         
0422         if (M_init_first)
0423         {
0424             if (EXSUCCEED!=ndrx_fpinit())
0425             {
0426                 MUTEX_UNLOCK_V(M_initlock);
0427                 return NULL;    /**< return here! */
0428             }
0429         }
0430         MUTEX_UNLOCK_V(M_initlock);
0431     }
0432     
0433     /* run all malloc */
0434     if (NDRX_UNLIKELY(M_malloc_all))
0435     {
0436         addr=malloc(size);
0437         NDRX_FPDEBUG("all malloc %p", addr);
0438         return (void *)addr;
0439     }
0440     
0441     /* bin search... for the descriptor */
0442     if (flags & NDRX_FPSYSBUF)
0443     {
0444         poolno = NDRX_FPA_MAX-1;
0445     }
0446     else
0447     {
0448         DO_BIN_SEARCH;
0449     }
0450     
0451     if (NDRX_UNLIKELY(EXFAIL==poolno))
0452     {
0453         /* do malloc.., arb size */
0454         addr = (ndrx_fpablock_t *)NDRX_MALLOC(size+sizeof(ndrx_fpablock_t));
0455         
0456         NDRX_FPDEBUG("Arb size alloc %p", addr);
0457         
0458         if (NULL==addr)
0459         {
0460             goto out_err;
0461         }
0462         addr->flags=NDRX_FPABRSIZE;
0463         addr->magic = NDRX_FPA_MAGIC;
0464         addr->next = NULL;
0465         addr->poolno = EXFAIL;
0466     }
0467     else
0468     {
0469         
0470         if (M_fpa_pools[poolno].flags & NDRX_FPNOPOOL)
0471         {
0472             /* return new block as no pool used for particular size */
0473             addr = (ndrx_fpablock_t *)NDRX_MALLOC(M_fpa_pools[poolno].bsize+sizeof(ndrx_fpablock_t));
0474             NDRX_FPDEBUG("no-pool block for %d alloc %p", poolno, addr);
0475             
0476             if (NULL==addr)
0477             {
0478                 goto out_err;
0479             }
0480             
0481             addr->poolno = poolno;
0482             addr->flags=NDRX_FPNOPOOL;
0483             addr->magic = NDRX_FPA_MAGIC;
0484             addr->next = NULL;
0485         }
0486         
0487         /* get from stack alloc if needed */
0488         NDRX_SPIN_LOCK_V(M_fpa_pools[poolno].spinlock);
0489         
0490         if (NULL!=M_fpa_pools[poolno].stack)
0491         {
0492             addr = M_fpa_pools[poolno].stack;
0493             M_fpa_pools[poolno].stack=M_fpa_pools[poolno].stack->next;
0494             /* reduce the block count */
0495             M_fpa_pools[poolno].cur_blocks--;
0496         }
0497 #ifdef NDRX_FPA_STATS
0498         else
0499         {
0500             M_fpa_pools[poolno].allocs++;
0501         }
0502 #endif
0503         
0504         NDRX_SPIN_UNLOCK_V(M_fpa_pools[poolno].spinlock);
0505         
0506         if (NULL==addr)
0507         {
0508             /* do malloc.. */
0509             if (NDRX_FPA_SIZE_SYSBUF==M_fpa_pools[poolno].bsize)
0510             {
0511                 /* size must be correctly passed in */
0512                 addr = (ndrx_fpablock_t *)NDRX_MALLOC(size+sizeof(ndrx_fpablock_t));
0513                 NDRX_FPDEBUG("Pool %d sysbuf alloc %p", poolno, addr);
0514             }
0515             else
0516             {
0517                 addr = (ndrx_fpablock_t *)NDRX_MALLOC(M_fpa_pools[poolno].bsize+sizeof(ndrx_fpablock_t));
0518                 NDRX_FPDEBUG("Pool %d block alloc %p", poolno, addr);
0519             }
0520             if (NULL==addr)
0521             {
0522                 goto out_err;
0523             }
0524             addr->flags=0;
0525             addr->magic = NDRX_FPA_MAGIC;
0526             addr->next = NULL;
0527             addr->poolno = poolno;
0528         }
0529         else
0530         {
0531             NDRX_FPDEBUG("Got from pool %d addr %p", poolno, addr);
0532         }
0533     }
0534     
0535 out:
0536                         
0537     return (void *) (((char *)addr) + sizeof(ndrx_fpablock_t));
0538 
0539 out_err:
0540     return NULL;
0541 }
0542 
0543 /**
0544  * Free up the Feedback Pool Allocator memory block
0545  * @param ptr ptr alloc'd by ndrx_fmalloc
0546  */
0547 expublic NDRX_API void ndrx_fpfree(void *ptr)
0548 {
0549     ndrx_fpablock_t *addr = (ndrx_fpablock_t *)(((char *)ptr)-sizeof(ndrx_fpablock_t));
0550     int poolno;
0551     int action_free = EXFALSE;
0552 #ifdef NDRX_FPA_STATS
0553     static int callnum=0;
0554     static MUTEX_LOCKDECL(callnum_lock);
0555 #endif
0556     
0557     if (NDRX_UNLIKELY(M_malloc_all))
0558     {
0559         /* free only use of direct memory.. */
0560         NDRX_FPDEBUG("M_alloc_all free %p", ptr);
0561         NDRX_FREE(ptr); 
0562         goto out;
0563     }
0564     
0565     if (NDRX_UNLIKELY(addr->magic!=NDRX_FPA_MAGIC))
0566     {
0567         ssize_t wret;
0568         /* signal safe error msg */
0569 #define ERR_MSG1    "***************************************************\n"
0570 #define ERR_MSG2    "* INVALID FPA FREE: Invalid magic                 *\n"
0571 #define ERR_MSG3    "***************************************************\n"
0572         
0573         wret=write(STDERR_FILENO, ERR_MSG1, strlen(ERR_MSG1));
0574         wret=write(STDERR_FILENO, ERR_MSG2, strlen(ERR_MSG2));
0575         wret=write(STDERR_FILENO, ERR_MSG3, strlen(ERR_MSG3));
0576         abort();
0577     }
0578     
0579     /* remove arb size */
0580     if (NDRX_UNLIKELY(addr->flags & NDRX_FPABRSIZE))
0581     {
0582         NDRX_FPDEBUG("Arb/nopool free %p", addr);
0583         NDRX_FREE(addr); 
0584         goto out;
0585     }
0586     
0587     /* decide the feedback, at hits level we free up the buffer */
0588     poolno = addr->poolno;
0589     
0590     if (M_fpa_pools[poolno].flags & NDRX_FPNOPOOL)
0591     {
0592         NDRX_FPDEBUG("fpnopool %d free %p", poolno, addr);
0593         NDRX_FREE(addr); 
0594         goto out;
0595     }
0596     
0597     NDRX_SPIN_LOCK_V(M_fpa_pools[poolno].spinlock);
0598     
0599     /* Add back to the pool
0600      */
0601     if (M_fpa_pools[poolno].cur_blocks >= M_fpa_pools[poolno].num_blocks)
0602     {
0603         action_free = EXTRUE;
0604         NDRX_FPDEBUG("No space or hits in pool free up %p cur_hist=0", addr);
0605     }
0606     else
0607     {
0608         /* add block to stack */
0609         addr->next = M_fpa_pools[poolno].stack;
0610         M_fpa_pools[poolno].stack = addr;
0611         M_fpa_pools[poolno].cur_blocks++;
0612         NDRX_FPDEBUG("Add to pool %d: %p", poolno, addr);
0613     }
0614     
0615     NDRX_SPIN_UNLOCK_V(M_fpa_pools[poolno].spinlock);
0616     
0617 #ifdef NDRX_FPA_STATS
0618     MUTEX_LOCK_V(callnum_lock);
0619     callnum++;
0620 
0621     if ( callnum > 100)
0622     {
0623         int i;
0624         for (i=0; i<N_DIM(M_fpa_pools); i++)
0625         {   
0626             userlog("bsize %d allocs: %d", M_fpa_pools[i].bsize, M_fpa_pools[i].allocs);
0627         }
0628         callnum=0;
0629     }
0630     MUTEX_UNLOCK_V(callnum_lock);
0631 #endif
0632         
0633     if (action_free)
0634     {
0635         NDRX_FPDEBUG("Action free %p", addr);
0636         NDRX_FREE(addr);
0637     }
0638 out:    
0639     return;
0640 }
0641 
0642 /**
0643  * Reallocate memory block. If growing up, then moving to next (or free style
0644  * memory pool).
0645  * If shrinking then move to smaller pool, or stay in the first 256 byte pool
0646  * @param ptr to current memory block
0647  * @param size new memory size to allocate
0648  * @return alloc'd memory block or NULL on error (org ptr keeps)
0649  */
0650 expublic void *ndrx_fprealloc(void *ptr, size_t size)
0651 {
0652     int poolno=EXFAIL;
0653     ndrx_fpablock_t *addr;
0654     
0655     if (NULL==ptr)
0656     {
0657         addr=ndrx_fpmalloc(size, 0);
0658         NDRX_FPDEBUG("ndrx_fprealloc ret %p", ret);
0659         return addr;
0660     }
0661     
0662     if (NDRX_UNLIKELY(M_malloc_all))
0663     {
0664         /* free only use of direct memory.. */
0665         NDRX_FPDEBUG("M_alloc_all realloc ptr=%p %size=zu", ptr, size);
0666         addr=(ndrx_fpablock_t *)NDRX_REALLOC(ptr, size);
0667         return (void *)addr;
0668     }
0669     
0670     addr = (ndrx_fpablock_t *)(((char *)ptr)-sizeof(ndrx_fpablock_t));
0671     
0672     /* check the descriptor 
0673      * OK we shall get the boundries.
0674      * Get current descr
0675      * Get next descr -> grow to this size if needed
0676      * Get previous descr -> shrink to this size if needed
0677      */
0678     
0679     DO_BIN_SEARCH;
0680     
0681     /* check the new pool */
0682     
0683     if (EXFAIL!=poolno)
0684     {
0685         if (addr->poolno==poolno)
0686         {
0687             NDRX_FPDEBUG("No pool changed %d", poolno);
0688             goto out;
0689         }
0690         else
0691         {
0692             NDRX_FPDEBUG("Change pool from %d to %d", addr->poolno, poolno);
0693             /* realloc to new pool */
0694             addr=(ndrx_fpablock_t *)NDRX_REALLOC(addr, M_fpa_pools[poolno].bsize+sizeof(ndrx_fpablock_t));
0695             if (NULL==addr)
0696             {
0697                 goto out_err;
0698             }
0699             addr->poolno=poolno;
0700             addr->flags=0;
0701         }
0702     }
0703     else
0704     {
0705         /* Target shall be moved to free style */   
0706         NDRX_FPDEBUG("Realloc to arb size (old pool: %d)", addr->poolno);
0707         addr=(ndrx_fpablock_t *)NDRX_REALLOC(addr, size+sizeof(ndrx_fpablock_t));
0708         if (NULL==addr)
0709         {
0710             goto out_err;
0711         }
0712         /* set free style flag */
0713         addr->flags=NDRX_FPABRSIZE;
0714         addr->poolno=EXFAIL;
0715         goto out;
0716     }
0717     
0718 out:
0719     return (void *) (((char *)addr) + sizeof(ndrx_fpablock_t));
0720 
0721 out_err:
0722     return NULL;
0723 
0724 }
0725 
0726 /* vim: set ts=4 sw=4 et smartindent: */